What I want to do:
I have a Game based on CrySDK which is DirectX11 and I want to draw an ingame overlay like the steam overlay.
-> I write C# since I don't know any C++, so I'm looking for ways to do this in C#.
-> I use EasyHook and SharpDX Libaries because it seems this is the best way to go.
-> I found a reference project which is apparently some kind of hack for SC2, I'm just interested in the overlay part however.
-> I use Visual Studio 2013
-> For now I'd be happy if I could draw random stuff inside a game at all
What I did so far:
I was looking through google and SO search results, problem is, that either the stuff is in C++, C or other, the results are from 2010 and not up to date with the current dx11, contain dead links or are unusable for any other reasons. This covers 95% of all I've turned up myself, some usuable hints have been included into my code.
I managed to create a Injector.dll and inject it into the game (at least i think it is injected, haven't had any usuable results so far)
What I have:
The file which does the injection:
...
// Try inject thingy
EasyHook.Config.Register("Star Citizen Noise.sc Client Overlay",
// "Direct3D9Hook.dll",
"SharpDX.dll",
"SharpDX.Direct3D11.dll",
"Injector.dll");
// Do the inject
RemoteHooking.Inject(scProcess.Id, InjectionOptions.DoNotRequireStrongName, "Injector.dll", "Injector.dll", "Star Citizen Noise.sc Injector.dll");
Console.WriteLine("DLL Injected.");
...
The injector.dll itself consists of this file, called Hooks/Graphics/Direct3D11Hook.cs (I tried to keep the structure similar to the oter sc2 reference project)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Runtime.InteropServices;
using EasyHook;
using SharpDX;
using SharpDX.Direct3D11;
using Rectangle = SharpDX.Rectangle;
namespace Injector.Hooks.Graphics
{
public class Direct3D11Hook : HookBase
{
private Device device = null;
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
private delegate Result EndSceneDelegate(IntPtr devicePointer);
public delegate void EndSceneEventDelegate(ref IntPtr devicePointer);
public event EndSceneEventDelegate OnEndScene;
private Result EndScene(IntPtr devicePointer)
{
try
{
//this.Log.LogMethodSignatureTypesAndValues(devicePointer);
//GetOrCreateDevice
if (this.device == null)
this.device = Device.FromPointer<Device>(devicePointer);
if (this.OnEndScene != null)
this.OnEndScene(ref devicePointer);
System.Drawing.Graphics g = System.Drawing.Graphics.FromHdc(devicePointer);
//System.Drawing.Graphics g = System.Drawing.Graphics.FromHwndInternal(devicePointer);
// lets try to draw something
Pen myPen = new Pen(System.Drawing.Color.Pink, 4);
System.Drawing.Point P1 = new System.Drawing.Point(50, 50);
System.Drawing.Point P2 = new System.Drawing.Point(500, 500);
g.DrawLine(myPen, P1, P2);
g.Dispose();
//this.device.EndScene();
return Result.Ok;
}
catch (SharpDXException ex)
{
//Log.Warn(ex);
Console.WriteLine(ex);
return ex.ResultCode;
}
catch (Exception ex)
{
//this.Log.Fatal(ex);
Console.WriteLine(ex);
return Result.UnexpectedFailure;
}
}
public override void Install()
{
try
{
EndSceneDelegate esd = new EndSceneDelegate(this.EndScene);
}
catch (Exception)
{
throw;
}
}
public override void Uninstall()
{
}
}
}
Here I tried to provide an override function for the EndScene function, because i think this is where I need to be. Needless to say, nothing appears to be drawn.
The delegate definitions are somewhat of a copypaste from the reference project however I have yet to find out how to actually hook my function into the render pipeline and/or react to events which might help my cause.
There is also this huge file [https://github.com/jasonpang/Starcraft2Hook/blob/master/Game/Hooks/Graphics/Direct3D9.cs] which defines function addresses which seems to work for DX9, I don't think that it can just be copy pasted and used for DX11 as well, so probably there are new function addresses in DX11? How can I find those? Where do I need to look? Is it something SharpDX can help me with?
TL;DR
Want to create steam-like overlay for DX11 game, need to hook into D3D stuff and magic and shit, got dll inject working, need help with pipeline injection
Related
I am trying to fetch events from the TaiPan Realtime COM server. I am able to extract other data from there. Accessing keys is working correctly.
But when i try to fetch events, the function is not fired somehow. Hopefully this is a small mistake. For better readability i made a small test code, which is easyer to read for you. After adding those ids to the Stream the Visual Basic debugger is working and it show cpu activity for com_test.
So i gues events are there but i made mistake in eventhandling somehow.
Thanks for help.
using System;
using System.Collections.Generic;
using TaiPanRTLib;
namespace com_test
{
class Program
{
static void Main(string[] args)
{
var handle = new handle();
handle.start();
Console.ReadLine();
}
}
public class handle
{
public int counter;
// this is a list contains the internal numbers of the taipan Software
public static List<int> numbercodes = new List<int>(new int[] { 78379670, 78379685, 78379692, 78379669, 78379729, 78379672, 78379674, 78379698, 78379682, 78379681, 78379704, 78379689, 78379694, 78379673, 78379697, 78379687, 78379702, 78379690, 78379668, 78379671, 78379715, 78379666, 78379706, 78379727, 78379679, 127289939, 78379677, 78379693, 78379676, 78379678, 78379680, 78379688, 78379726, 78379686, 78379696, 78379675, 78379667, 78379703, 78379691, 78379684, 78379700, 78379699, 78379705, 78379695, 78379701, 78379664, 78379716, 78379982, 78379665, 78379707, 78379728, 78379717, 78379719, 7837971 });
void TPRTDataStream_Bezahlt(int SymbolNr, float Kurs, float Volume, DateTime Zeit)
{
Console.WriteLine("peng"); // never see this in window - so not fired?
counter += 1;
}
public void start()
{
TaiPanRealtime TPRTObject = new TaiPanRealtime(); // connects to launches Application
DataStream TPRTDataStream = (DataStream)TPRTObject.DataStream; // attach to the DataStream Object.
foreach (int db_num in numbercodes)
{
TPRTDataStream.Add(db_num, 0); // This adds the internal dbnumber to the Stream
}
TPRTDataStream.Bezahlt+=new _IDataStreamEvents_BezahltEventHandler(TPRTDataStream_Bezahlt);
while (true)
{
Console.WriteLine(counter); // counter stays 0 all the time
System.Threading.Thread.Sleep(1000);
};
}
}
}
I want to post the solution TaiPan service found out. To handle the events correctly you need to set "Embed Interop Types" to false in the reference properties of visual basic. here is a screenshot:
screenshot properties
hope this helps others.
I'm trying to add custom coloring for only certain keywords in my Visual Studio editor for C# code. I want to be able to color any type that implements IDisposable as a different color. Ideally I'd like to create a simple list of classes/interfaces that derive from IDisposable in some sort of configuration that I can edit. (Although if you said there was a method/plugin that would automatically find all disposable types and color them independently that would be the Holy Grail).
I've done a ton of research and it looks like an "editor classifier" extension might do the trick. However I created one that merely tries to color the word "Stream" and although it does hit my code that attempts to highlight that word, it does not end up highlighted in the editor.
I have added my VS extension to Github here
This really seems like this should be fairly straightforward but I have gone down many alleys on this one only to find dead-ends. Is there a simpler way to do this, or is my extension broken?
Update
Very strange. I just ran my extension again and although it does not highlight the text in the editor it highlights all instances of "Stream" in the popup text when you hover over a type/variable! Is there any way to get it to apply to the editor?
Depending on wether you are using Jetbrains Resharper or not you may write a plugin for that. That way you are able not only to add visual notification of IDisposable on a variable but also provide quickfixes if, and only if, it is not beeing called, which is what i am assuming you want to catch. Mind you that i can imagine that there's already a R# plugin for that. I know i've considered this too, but i was too lazy to write a plugin for that.
Don't get me wrong btw - If you're not using r# yet you should consider trying it out.
Among others you'd be working with this: API-QuickFix
There are also ways to define custom keywords, as resharper does, given by a custom markup and apply quickfixes to that.
PS: No i don't work at jetbrains. it's just that good :)
UPDATE:
potential VS Extension fix?
check this one out: MSDN Link Highlighting Text
I tried opening your github project but couldn't so i thought i'll just check msdn instead. it seems you are deriving from the wrong class to fulfill your needs?
MSDN keyword "Editors - Extending the Editor - Walkthrough: Highlighting Text"
I know SO wants code on the site, but msdn links going down is rather unlikely and with the given information the content can be found easily enough :)
I'm a bit late to the party, but hey, why not throw my 2 cents in.
As you've explained in your question, your project has two basic parts:
Finding the classes that implement IDisposable
Highlighting them
The first is by far the hardest, though not impossible. A word-list based approach is probably the simplest, though it should be possible with Roslyn to figure out on the fly which classes inherit IDisposible.
You could also always resort to loading the project's compiled .exe/.dll in the background after a build and figuring out what the types are there, but you'd still have to write some magic glue code to figure out what short class names in the code referred to what actual full-name classes in the assembly.
The second part, highlighting, is quite easy once you know how to do it (it helps that I've spent the last several months working full-time on extending VS). Of course, with Visual Studio, nothing is as simple as it looks (despite the efforts of Microsoft to try to make it user-friendly). So, I've built a sample extension that highlights just classes named "Stream" within C# files to get you started.
The relevant code is below, and the full project source is on GitHub). It starts with a classification-tagger provider:
[Export(typeof(ITaggerProvider))]
[ContentType("CSharp")]
[TagType(typeof(ClassificationTag))]
[Name("HighlightDisposableTagger")]
public class HighlightDisposableTaggerProvider : ITaggerProvider
{
[Import]
private IClassificationTypeRegistryService _classificationRegistry = null;
[Import]
private IClassifierAggregatorService _classifierAggregator = null;
private bool _reentrant;
public ITagger<T> CreateTagger<T>(ITextBuffer buffer) where T : ITag
{
if (_reentrant)
return null;
try {
_reentrant = true;
var classifier = _classifierAggregator.GetClassifier(buffer);
return new HighlightDisposableTagger(buffer, _classificationRegistry, classifier) as ITagger<T>;
}
finally {
_reentrant = false;
}
}
}
Then the tagger itself:
public class HighlightDisposableTagger : ITagger<ClassificationTag>
{
private const string DisposableFormatName = "HighlightDisposableFormat";
[Export]
[Name(DisposableFormatName)]
public static ClassificationTypeDefinition DisposableFormatType = null;
[Export(typeof(EditorFormatDefinition))]
[Name(DisposableFormatName)]
[ClassificationType(ClassificationTypeNames = DisposableFormatName)]
[UserVisible(true)]
public class DisposableFormatDefinition : ClassificationFormatDefinition
{
public DisposableFormatDefinition()
{
DisplayName = "Disposable Format";
ForegroundColor = Color.FromRgb(0xFF, 0x00, 0x00);
}
}
public event EventHandler<SnapshotSpanEventArgs> TagsChanged = delegate { };
private ITextBuffer _subjectBuffer;
private ClassificationTag _tag;
private IClassifier _classifier;
private bool _reentrant;
public HighlightDisposableTagger(ITextBuffer subjectBuffer, IClassificationTypeRegistryService typeService, IClassifier classifier)
{
_subjectBuffer = subjectBuffer;
var classificationType = typeService.GetClassificationType(DisposableFormatName);
_tag = new ClassificationTag(classificationType);
_classifier = classifier;
}
public IEnumerable<ITagSpan<ClassificationTag>> GetTags(NormalizedSnapshotSpanCollection spans)
{
if (_reentrant) {
return Enumerable.Empty<ITagSpan<ClassificationTag>>();
}
var tags = new List<ITagSpan<ClassificationTag>>();
try {
_reentrant = true;
foreach (var span in spans) {
if (span.IsEmpty)
continue;
foreach (var token in _classifier.GetClassificationSpans(span)) {
if (token.ClassificationType.IsOfType(/*PredefinedClassificationTypeNames.Identifier*/ "User Types")) {
// TODO: Somehow figure out if this refers to a class which implements IDisposable
if (token.Span.GetText() == "Stream") {
tags.Add(new TagSpan<ClassificationTag>(token.Span, _tag));
}
}
}
}
return tags;
}
finally {
_reentrant = false;
}
}
}
I've only tested this on VS2010, but it should work for VS2013 too (the only thing that might be different is the class classification name, but that's easy to discover with a well-placed breakpoint). I've never written an extension for VS2012, so I can't comment on that, but I know it's quite close to VS2013 in most respects.
So, one possible solution(I believe this one works):
1) Create your own content type which inherits from csharp.
2) Create new TextViewCreationListener which will swap out all "csharp" content types with your own one, thus potentially "disarming" all the other classifiers.
3) Register your classifier to handle your own content type.
Here is some of the code:
[Export(typeof(IVsTextViewCreationListener))]
[ContentType("csharp")]
[TextViewRole(PredefinedTextViewRoles.Editable)]
class TextViewCreationListener : IVsTextViewCreationListener {
internal readonly IVsEditorAdaptersFactoryService _adaptersFactory;
[Import] internal IContentTypeRegistryService ContentTypeRegistryService = null;
[ImportingConstructor]
public TextViewCreationListener(IVsEditorAdaptersFactoryService adaptersFactory) {
_adaptersFactory = adaptersFactory;
}
#region IVsTextViewCreationListener Members
public void VsTextViewCreated(VisualStudio.TextManager.Interop.IVsTextView textViewAdapter) {
var textView = _adaptersFactory.GetWpfTextView(textViewAdapter);
var myContent = ContentTypeRegistryService.GetContentType(MyContentType);
if(myContent == null)
{
ContentTypeRegistryService.AddContentType(MyContentType, new[] {"csharp"});
myContent = ContentTypeRegistryService.GetContentType(MyContentType);
}
// some kind of check if the content type is not already MyContentType.
textView.TextBuffer.ChangeContentType(myContent, null);
}
#endregion
}
And now, just modify your IClassifierProvider to register with your own content type, as such: [ContentType(MyContentType)]
Iin your own IClassifier, you can basically do your own calculation and once you think you can't handle the stuff, you could pass the control to other classifiers.
If you use MEF and import IClassifierAggregatorService, you can get a "MASTER-classifier" which will run all the logic for you. I haven't implemented it yet, but I've suggestes something similiar in the past, and it seemed to work. Alternatively you could maybe use [ImportMany] with List<IClassifier> and filter out the csharp ones?!
I'm converting an .NET Windows application for Mono to run on Linux (Ubuntu). One of the features depends on a native library (user32.dll). The Mono guide that talks about conversion of applications (Linux Platform Differences) suggests that one approach would be to modify this code.
I'm trying to use GDK to access the Title of a Gdk.Window that I had access through the property Gdk.Global.ActiveWindow. But I found this error at compile time:
Error CS0154: The property or indexer `Gdk.Window.Title` cannot be used in this context because it lacks the `get` accessor (CS0154) (GetActiveWindow)
If i remove the code that reads de Title property of activeW, everything works fine. There is another way to read this property?
Here my unit of work:
using System;
using Gtk;
using Gdk;
using System.Threading;
namespace GetActiveWindow
{
class GdkApp : Gtk.Window
{
public static void Main ()
{
Application.Init ();
new GdkApp ();
Application.Run ();
}
public GdkApp () : base("Simple App")
{
SetDefaultSize (150, 150);
ShowAll();
while (true) {
var activeW = Gdk.Global.ActiveWindow;
Console.WriteLine("Active Window: {0}",activeW.Title); // Where my compile error happens.
Console.WriteLine("Simple App Window: {0}",this.Title); // This code works perfectily.
Thread.Sleep(1000);
}
}
}
}
I think that with Gdk is imposible. Try it with Wnck library giving to a C compiler this '-DWNCK_I_KNOW_THIS_IS_UNSTABLE' and works but with a warning: Unhandled action type _OB_WM_ACTION_UNDECORATE
Sorry I have used genie instead vala.
//valac *.gs --pkg gtk+-3.0 --pkg libwnck-3.0 -X '-DWNCK_I_KNOW_THIS_IS_UNSTABLE'
init
Gtk.init(ref args)
var ventana= new win()
ventana.inicio()
ventana.printinfo()
Gtk.main()
class win:Gtk.Window
won:weak GLib.List of Wnck.Window
def inicio()
var button= new Gtk.Button()
button.clicked.connect(printinfo)
this.add(button)
this.show_all()
def printinfo()
won= Wnck.Screen.get_default().get_windows()
won.foreach(allwin)
def allwin(w:Wnck.Window)
if w.is_skip_tasklist() or w.is_skip_pager()
pass
else
print w.get_name()
In my "LuaTest" namespace I have a class called "Planet". The C# code reads like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LuaInterface;
namespace LuaTest
{
public class Planet
{
public Planet(string name)
{
this.Name = name;
}
public Planet() : this("NoName") { }
public string Name
{
get;
private set;
}
public void printName()
{
Console.WriteLine("This planet's name is {0}", Name);
}
}
}
Then I built LuaTest.dll and copied this file to the same folder where my Lua script is saved. In the Lua script I wrote:
--define Path for required dlls
package.cpath = package.cpath .. ";" .. "/?.dll"
package.path = package.path .. ";" .. "/?.dll/"
require 'luanet'
luanet.load_assembly("LuaTest")
local Planet = luanet.import_type("LuaTest.Planet")
local planet = Planet("Earth")
planet.printName()
However, this piece of code does not work. Lua interpreter throws this error:
lua: dllTest.lua:7: attempt to call local 'Planet' (a nil value)
I suspect that my LuaTest assembly is not loaded at all. Could anyone point out where I did wrong? I would very much appreciate it, since I've been stuck by this problem for days.
Also it might be helpful to add that my LuaInterface.dll is the rebuilt version in .NET4.0 environment.
So I spent a LOT of time similarly. What really drove me bonkers was trying to get Enums working. Eventually I ditched my project for a very simplified console application, very similar (ironically also named 'LuaTest').
Edit: I've noted that the initial "luanet.load_assembly("LuaTest")" appears superfluous. Works with it, or surprisingly without it.
Another Edit: As in my badly edited comment below, when I removed:
print(luanet.LuaTest.Pointless)
It all stopped working (LuaTest.Pointless became nil). But adding the luanet.load_assembly("LuaTest") then makes it work. It may be that there is some sort of odd implicit load in the print or in just expressing they type. Very Strange(tm).
In any case, it seems to work for me (note: after a lot of experimentation). I don't know why yours is failing, I don't note any real difference, but here's all my code in case someone else can spot the critical difference:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LuaInterface;
namespace LuaTest
{
public class Program
{
static void Main(string[] args)
{
Lua lua = new Lua();
lua.DoFile("test.lua");
}
public int some_member = 3;
}
public class Pointless
{
public enum AnEnum
{
One,
Two,
Three
};
public static string aStaticInt = "This is static.";
public double i;
public string n = "Nice";
public AnEnum oneEnumVal = AnEnum.One;
private AnEnum twoEnumVal = AnEnum.Two;
private string very;
public Pointless(string HowPointLess)
{
i = 3.13;
very = HowPointLess;
}
public class MoreInnerClass
{
public string message = "More, please!";
}
public void Compare(AnEnum inputEnum)
{
if (inputEnum == AnEnum.Three)
Console.WriteLine("Match.");
else
Console.WriteLine("Fail match.");
}
}
}
and test.lua:
luanet.load_assembly("LuaTest")
--Pointless is a class in LuaTest assembly
local Pointless = luanet.import_type("LuaTest.Pointless")
print(Pointless)
--Gives 'ProxyType(LuaTest.Pointless): 46104728
print(Pointless.aStaticInt)
--'This is static.'
--Fails if not static, as we expect
--Instantiate a 'Pointless'.
local p = Pointless("Very")
print(p)
--Gives 'LuaTest.Pointless: 12289376'
--Now we can get at the items inside the Pointless
--class (well, this instance, anyway).
local e = p.AnEnum;
print(e)
--ProxyType(LuaTest.Pointless+AnEnum): 23452342
--I guess the + must designate that it is a type?
print(p.i)
--3.14
print(p.oneEnumVal)
--Gives 'One: 0'
print(p.twoEnumVal)
--Gives 'twoEnumVal'... private
--behaves very differently.
print(e.Two:ToString())
--Gives 'Two'
local more = p.MoreInnerClass()
print(more.message)
--'More, Please!'
--create an enum value here in the script,
--pass it back for a comparison to
--the enum.
local anotherEnumVal = p.AnEnum.Three
p:Compare(anotherEnumVal)
--outputs 'Match'
Having spent the last several days working on a project that required this exact functionality from LuaInterface, I stumbled across a piece of Lua code that turned out to be the perfect solution (see Reference 1). Whilst searching for this solution, I noticed this question and figured I'd drop my two cents in.
To apply this solution, I merely run the CLRPackage code while initializing my LuaInterface Lua object. However, the require statement works just as well.
The code provided in reference 1 allows the use of import statements, similar to C# using statements. Once an assembly is imported, its members are accessible in the global namespace. The import statement eliminates the need to use load_assembly or import_type (except in situations in which you need to use members of the same name from different assemblies. In this scenario, import_type would be used similar to C# using NewTypeName = Assembly.OldTypeName).
import "LuaTest"
planet = Planet("Earth")
planet:printName()
This package also works great with enums!
Further information regarding the use of this package may be found at Reference 2.
Hope this helps!
Reference 1: https://github.com/stevedonovan/MonoLuaInterface/blob/master/bin/lua/CLRPackage.lua
Reference 2: http://penlight.luaforge.net/project-pages/penlight/packages/LuaInterface/
I spent some time in binding C# dll to lua. Your posts were helpful but something was missing. The following solution should work:
(Make sure to change your compiler to .NET Framework 3.5 or lower!)
Planet.dll:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Planets
{
public class Planet
{
private string name;
public string Name
{
get { return name; }
set { this.name = value; }
}
private float diameter;
public float Diameter
{
get { return diameter; }
set { this.diameter = value; }
}
private int cntContinents;
public int CntContinents
{
get { return cntContinents; }
set { this.cntContinents = value; }
}
public Planet()
{
Console.WriteLine("Constructor 1");
this.name = "nameless";
this.diameter = 0;
this.cntContinents = 0;
}
public Planet(string n, float d, int k)
{
Console.WriteLine("Constructor 2");
this.name = n;
this.diameter = d;
this.cntContinents = k;
}
public void testMethod()
{
Console.WriteLine("This is a Test!");
}
}
}
Use the code above, paste it into your class library project and compile it with .NET smaller or equal 3.5.
The location of the generated DLL needs to be known by the lua enviroment. Paste it e.g at "clibs"-folder or another well known lua system path. Then try to use the following lua example. It should work.
Test1.lua: (Option 1 with "import" from CLRPackage)
require "luanet"
require "CLRPackage"
import "Planet"
local PlanetClass = luanet.import_type("Planets.Planet")
print(PlanetClass)
local PlanetObject1 = PlanetClass()
print(PlanetObject1)
local PlanetObject2 = PlanetClass("Earth",6371.00*2,7)
print(PlanetObject1.Name)
PlanetObject1.Name = 'Mars'
print(PlanetObject1.Name)
print( "Planet " ..
PlanetObject2.Name ..
" is my home planet. Its diameter is round about " ..
PlanetObject2.Diameter .. "km." ..
" Our neighour is " ..
PlanetObject1.Name)
Test2.lua: (Option 2 with "load_assembly")
require "luanet"
require "CLRPackage"
luanet.load_assembly("Planet")
local PlanetClass = luanet.import_type("Planets.Planet")
print(PlanetClass)
local PlanetObject1 = PlanetClass()
print(PlanetObject1)
local PlanetObject2 = PlanetClass("Earth",6371.00*2,7)
print(PlanetObject1.Name)
PlanetObject1.Name = 'Mars'
print(PlanetObject1.Name)
print( "Planet " ..
PlanetObject2.Name ..
" is my home planet. Its diameter is round about " ..
PlanetObject2.Diameter .. "km." ..
" Our neighour is " ..
PlanetObject1.Name)
In both cases the console output will look like this:
ProxyType(Planets.Planet): 18643596
Constructor 1
Planets.Planet: 33574638
Constructor 2
nameless
Mars
Planet Earth is my home planet. Its diameter is round about 12742km. Our neighbour is Mars
I hope its helps some of you.
Edit 1:
by the way, a method call from lua looks like this:
PlanetObject1:testMethod()
PlanetObject2:testMethod()
Edit 2:
I found different dll's whitch needed to be handled differently. One needed the "import"-function and another needed the "load_assembly"-function. Keep that maybe in mind!
I need some advice on how to do the following in either C# and VB.net.
In C++, in my header file I do the following:
#define StartButtonPressed Input[0]==1 // Input is an array declared in .cpp file
In my .cpp file, i have a code something like this:
if(StartButtonPressed)
// do something
The reason of me doing so is so that my code is easier to read.
I tried the same thing in C# but it got error. How could I do the same thing in C# and VB.Net?
Please advice. Thanks.
There is no good reason to use a macro for this in C++; you could just as easily make it a function and the code would be far cleaner:
bool IsStartButtonPressed()
{
return Input[0] == 1;
}
Input should also probably be passed as an argument to the function, but it's hard to tell exactly where that is coming from.
You're best off creating a property in your class
protected bool StartButtonPressed {
get { return Input[0] == 1; }
}
then your code can be as before
.
.
.
if(StartButtonPressed) {
.
.
.
}
However for consistency with the .net framework I'd suggest calling the property IsStartButtonPressed
If you need to to be evaluated at the point of the if statement then you really need a function or a property. However is this is one time evaluation you can use a field
bool isStartButtonPressed = Input[0] ==1;
If you want may classes to have this functionality then I'd recommend a static function from another class, something like
public static class ButtonChecker {
public static bool IsPressed(int[] input) {
return input[0] == 1;
}
}
Then you call it anywhere with
if(ButtonChecker.IsPressed(Input)) {
.
.
}
But ultimately you cannot use macro's like you're used in C/C++. You shouldn't be worried about performance of properties and functions like this as the CLR jit compiler implementation is very very good for them
Here is an example program:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
namespace ConsoleApplication1 {
public static class ButtonChecker {
public static bool IsPressed(int[] input) {
return input[0] == 1;
}
}
static class Program {
public static void Main(){
int[] Input = new int[6] { 1, 0, 2, 3,4 , 1 };
for(int i = 0; i < Input.Length; ++i){
Console.WriteLine("{0} Is Pressed = {1}", i, ButtonChecker.IsPressed(Input));
}
Console.ReadKey();
}
}
}
You could use an enum
public enum buttonCode
{
startButton = 0,
stopButton = 1
// more button definitions
}
Then maybe one function
public bool IsButtonPressed(b as buttoncode)
{
return Input[b] == 1;
}
Then your calls look like:
if IsButtonPressed(buttonCode.StartButton) { }
The only changes needed to switch button codes are then in the enum, not spread across multiple functions.
Edited to Add:
If you want individually named functions, you could do this:
public bool IsStartButtonPressed()
{
return Input[buttonCode.StartButton] == 1;
}
Still, all of the edits would be in the enum, not the functions.
Bjarne Stroustrup wrote:
The first rule about macros is: Do not use them if you do not have to. Almost every macro demonstrates a flaw in the programming language, in the program, or in the programmer.
It's worth noting two things here before saying anything else. The first is that "macro" can mean a very different thing in some other languages; one would not make the same statement about Lisp. the second is that Stroustrup is willing to take his share of the blame in saying that one reason for using macros is "a flaw in the programming language", so it's not like he's just being superior in condemning their use.
This case though isn't a flaw in the programming language, except that the language lets you do it in the first place (but has to, to allow other macros). The only purpose of this macro is to make the code harder to read. Just get rid of it. Replace it with some actual C# code like:
private bool StartButtonPressed
{
get
{
return Input[0]==1
}
}
Edit:
Seeing the comment above about wanting to be faster to code, I would do something like:
private enum Buttons
{
Start = 0,
Stop = 1,
Pause = 2,
/* ... */
}
private bool IsPressed(Buttons button)
{
return Input[(int)button] == 1;
}
And then call e.g. IsPressed(Buttons.Start). Then I'd fix the C++ to use the same approach too (in C++ I would even be able to leave out the Buttons. where I wanting particularly great concision).