I am rewriting the Betfair API to JSON from SOAP and I have started off the way I did it before as a console APP which is then called from a task scheduler or win service.
However now I have been asked to do various different jobs with the code and I don't want to write a console app for each job (different sites want prices, bets placed etc)
The new codebase is much larger than the old one and I would have been able to copy the 4 files from the old system into a DLL app and then create various console apps/services to implement the DLL - however because it's 40+ files I don't want a copy n paste job if possible.
Is there a way I can EASILY convert an existing console project into a class / DLL project with some tool or command in VS?
I want to be able to just then create simple apps that just go
BetfairBOT myBOT = new BetfairBOT()
myBOT.RunGetPrices();
or
BetfairBOT myBOT = new BetfairBOT()
myBOT.RunPlaceBets();
e.g 2/3 lines of code to implement my DLL that is registered to my app.
So without copy and paste can I do this.
I am using VS 2012, .NET 4.5 (or 4.0 if I need to depending on server), Windows 8.1
Any help would be much appreciated.
This answer is from here. while it used winforms instead of console application, I think you will be able to use it.
Steps for creating DLL
Step 1:- File->New->Project->Visual C# Projects->Class Library. Select your project name and appropriate directory click OK
After Clicking on button ‘OK’, solution explorer adds one C# class ‘Class1.cs’. In this class we can write our code.
When we double click on Class1.cs, we see a namespace CreatingDLL. We will be use this namespace in our project to access this class library.
Step 2:- Within Class1.cs we create a method named ‘sum’ that takes two integers value and return sum to witch method passed numbers.
using System;
namespace CreatingDLL
{
public class Class1
{
/// <summary>
/// sum is method that take two integer value and return that sum
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public int sum(int x, int y)
{
return x + y;
}
}
}
Step 3:- Now build the Application and see bin\debug directory of our project. ‘CreatingDLL.dll’ is created.
Now we create another application and take this DLL (CreatingDLL.dll) reference for accessing DLL’s method.
Steps for accessing created DLL
Step 4:- File->New->Project->Visual C# Projects->Windows Form Application.
Step 5:- Designed windows form as bellow figure.
Step 6:- Add reference of DLL (CreatingDLL) which we created before few minutes.
After adding reference of DLL, following windows will appear.
Step 7:- Write code on button click of Windows Form Application. Before creating object and making method of Add DLL, add namespace CreatedDLL in project as bellow code.
using System;
using System.Windows.Forms;
using CreatingDLL;
namespace AccessingDLL
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnAdd_Click(object sender, EventArgs e)
{
Class1 c1 = new Class1();
try
{
txtResult.Text = Convert.ToString(c1.sum(Convert.ToInt32(txtNumber1.Text), Convert.ToInt32(txtNumber2.Text)));
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
Step 8:- Now build the application and execute project and see output.
Edit: To change an application into a library do these steps
First, double click on Properties inside Solution Explorer window.
Then, On the openned page, change the Output Type from Console Application to Class Library
Related
I'm trying to pass a C# object to a WebView2 using AddHostObjectToScript. After not succeeding to retrieve the object from the webview, I've used the debugger and found out that the AddHostObjectToScript call is never completing.
Here is the full code snippet:
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class Example
{
public string Prop { get; set; } = "example";
}
namespace Example_UWP
{
public sealed partial class MainPage : Page
{
public MainPage()
{
InitializeComponent();
InitializeAsync();
}
public async Task InitializeAsync()
{
await ExampleView.EnsureCoreWebView2Async();
ExampleView.Source = new Uri("http://localhost:3000");
ExampleView.CoreWebView2.OpenDevToolsWindow();
ExampleView.CoreWebView2.AddHostObjectToScript("example", new Example());
}
}
}
The example object is as a result not available in chrome.webview.hostObjects or chrome.webview.hostObjects.sync. The function throws the following error:
The group or resource is not in the correct state to perform the requested operation.
I've tried different alternatives without success, such as:
Keeping a reference to the Example instance in an attribute inside Example_UWP to avoid potential GC
Adding the host object before and after each of the previous steps within InitializeAsync
Wait for the event NavigationCompleted to add the host object.
Wait for 5 seconds before adding the host object.
I'm using Microsoft.Web.WebView2 version 1.0.1264.42
In order to interact with your third-party lib, you need to add a very specific C++ project, Windows Runtime Component (C++/WinRT), to your solution that must be called WinRTAdapter.
Next, you must install a lib to your C++ project from NuGet called Microsoft.Web.WebView2:
After this is done, you must your third-party lib as a reference.
Next, go to your C++ project properties go to Common Properties and choose WebView2:
Here you have to do four changes:
Set Use WebView2 WinRT APIs to No.
Set Use the wv2winrt tool to Yes.
Set Use Javascript case to Yes.
Edit Include filters and add the following ones:
Windows.System.UserProfile
Windows.Globalization.Language
CallJSInterface
CallJSInterface is the name of my third-party's namespace.
You click on OK and build your C++ lib.
After you have built your C++ lib (WinRTAdapter), you must add it to your main project as a reference.
Now, we need to do some changes to be able to invoke the functions from our third-party lib. The first one is to register it. We do it in the same LoadLocalPage() function from before or on NavigationCompleted:
var namespacesName = "CallJSInterface";
var dispatchAdapter = new WinRTAdapter.DispatchAdapter();
core_wv2.AddHostObjectToScript(namespacesName, dispatchAdapter.WrapNamedObject(namespacesName, dispatchAdapter));
Where CallJSInterface is your namespace. After this, you need to register your function in your JS like this:
var callJS;
if (chrome && chrome.webview) {
chrome.webview.hostObjects.options.defaultSyncProxy = true;
chrome.webview.hostObjects.options.forceAsyncMethodMatches = [/Async$/];
chrome.webview.hostObjects.options.ignoreMemberNotFoundError = true;
window.CallJSInterface = chrome.webview.hostObjects.sync.CallJSInterface;
callJS = new CallJSInterface.CallJSCSharp();
}
Where CallJSInterface is one more time your namespace. Now, you can invoke JS like this (the async() is mandatory):
callJS.async().KeepScreenOn()
If you need more details, I have a full tutorial on my website:
https://supernovaic.blogspot.com/2022/10/from-webview-to-webview2-in-uwp.html
Suppose I have two files in my current working directory:
// file1.cs
Console.WriteLine("file1");
//file 2.cs
Console.WriteLine("file2");
In powershell, I do a dotnet new and delete the automatically generated Program.cs file. Then I do a dotnet build and get an error:
Only one compilation unit can have top level statements
I understand why this occurs, but I would like to be able to have full control of which .cs file is being targetted, while the other ones get ignored.
Is there any way to achieve this without having to create a whole new project for every file?
Doing this with .NET doesn't seem to be possible as of now. An issue on the dotnet/sdk GitHub has requested for this feature to be implemented.
However, you can use the C Sharp Compiler to compile a Windows executable and specify a .cs file with csc file1.cs
file1.cs:
using System;
Console.WriteLine("File 1");
https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/program-structure/top-level-statements
These files both use top-level statements. It implies that they both contain the Main method where program execution starts. You can only have one entry point. Generally, C# code is going to be contained within classes. Define a class in one (or both) files and put your methods within.
// Program.cs
public class Program
{
static void Main()
{
Console.WriteLine("Program.cs");
}
}
// Util.cs
public class Util
{
public static void Display()
{
Console.WriteLine("Util.cs");
}
}
I have a libary which needs to behave differently for console applications, desktop application (e.g. WPF), and for UWP apps.
How can I determine at run-time into which application type my libary is loaded?
Determining if it is a console application seems easy: How to tell if there is a console
For UWP, I can probably determine if WinRT is loaded. But how?
What distinguishing attributes do desktop applications have?
I ended up defining following enum:
public enum ExecutionMode
{
Console,
Desktop,
UniversalWindowsPlatform
}
which is passed to the constructor of the main class of my libary. Not a new idea, but very reliable (if used correctly).
Create a CustomAttribute in an assembly that is available to all of the applications like so
using System;
namespace MyNamespace.Reflection {
[System.AttributeUsage(AttributeTargets.Assembly)]
public class ApplicationTypeAttribute : Attribute {
public enum ApplicationTypes {
Console,
Desktop,
UWP,
ClassLibrary
}
public ApplicationTypeAttribute(ApplicationTypes appType) {
ApplicationType = appType;
}
public ApplicationTypes ApplicationType { get; private set; } = ApplicationTypes.Console;
}
}
Then add this attribute to your AssemblyInfo.cs file for a console application
using MyNamespace.Reflection;
[assembly: ApplicationType(ApplicationTypeAttribute.ApplicationTypes.Console)]
or a Desktop application
[assembly: ApplicationType(ApplicationTypeAttribute.ApplicationTypes.Desktop)]
etc.
Then wherever you want to check the calling type of the application that was started, use this
using MyNamespace.Reflection;
var assy = System.Relection.Assembly.GetEntryAssembly();
var typeAttribute = assy.GetCustomAttribute(typeof(ApplicationTypeAttribute));
if (typeAttribute != null) {
var appType = ((ApplicationTypeAttribute)typeAttribute).ApplicationType;
}
There is one caveat to this method. .NET Core apps have a different project structure and the AssemblyInfo.cs file is auto-generated at build time by default. You can override this behavior by specifying the following in the .csproj file in the Project node.
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
To match the old project file structure, you can create a Properties directory in the project directtory and then you can add an AssemblyInfo.cs file to that directory. Otherwise you can place the Custom Attribute definition in any file (after the usings and before the namespace declaration).
I am observing a very strange behavior in my simple C# console application. I can't understand why CLR is working that way under the hood. Here are my code samples:
My Main program:
class Program
{
static void Main(string[] args)
{
Employee emp = new Employee();
Console.WriteLine( emp.EmployeeName());
}
}
The console application project containing the above Main method references another C# class library project named CustomDataObjects. It is as below:
namespace CustomDataObjects
{
public class Employee
{
public string GetEmployeeName()
{
return "Foo";
}
}
}
I build everything and it works perfectly fine. Main function prints "Foo" on console.
Now I changed my CustomDataObjects project as below. I changed the signature of GetEmployeeName method and introduced a new mandatory parameter named empName
namespace CustomDataObjects
{
public class Employee
{
public string GetEmployeeName(string empName)
{
return empName;
}
}
}
I did not recompile my console project after making these changes. I simply recompiled CustomDataObjects project after making above changes. Then, I copied the newly built CustomDataObjects.dll and CustomDataObjects.pdb files into \bin\debug directory of main console project.
Now I try to run the executable file of main console application from bin\debug directory of main console project. To my surprise it doesn't crash. If I'm not wrong, on the second run CLR should have tried to look for definition of GetEmployeeName with older signature which doesn't have any parameter and since CustomDataObjects.dll has changed it should observe the mismatch and cause a run-time crash. Why did it not happen this way? My console application is running on .Net v4.0
The .NET Shell extension framework called SharpShell is great; I've developed a right-click file Shell ContextMenu "quite easily" that works selecting both files and directories.
Now I would like to develop a Shell ContextMenu by righ-clicking on an empty space (that is, on the Desktop or on a white spot while I'm inside a folder).
Is it possible do that still using SharpShell? Or do I need to move to a different solution?... and in 2nd case... what do you suggest?
Thanks
The two solutions presented below work, but in the meantime I have found that there is an easier solution that is actually already used in the samples that come with SharpShell.
See the CopyDirectoryLocationHandler class as an example of a context menu handler that is registered for the directory background (and the desktop):
[ComVisible(true)]
[COMServerAssociation(AssociationType.Class, #"Directory\Background")]
public class CopyDirectoryLocationHandler : SharpContextMenu
{
// ...
}
If you want the handler to only handle clicks on the desktop background, use this code instead:
[ComVisible(true)]
[COMServerAssociation(AssociationType.Class, #"DesktopBackground")]
public class CopyDirectoryLocationHandler : SharpContextMenu
{
// ...
}
Old obsolete answer:
You can use SharpShell for this purpose without problem. There are two possible approaches:
Register the Shell Extension to handle the folder background
yourself
or
Modify SharpShell to handle the registration of the
extension for the folder background for you.
Register the Shell Extension to handle the folder background yourself
Your shell extension is a COM server and as such is identified to the system via a GUID. This GUID is then used at places in the registry to register the COM extension for different purposes. When we manually want to register the extension for a purpose such as extending the context menu for folder backgrounds, it is best when our extension has a fixed GUID.
Currently your class looks like this:
[ComVisible(true)]
[COMServerAssociation(AssociationType.Directory)]
public class MyContextMenuExtension : SharpContextMenu
{
When compiling, the compiler will automatically generate a GUID to use for that class. But we can specify a specific one to use like this:
[Guid("A75AFD0D-4A63-41E3-AAAA-AD08A574B8B0")]
[ComVisible(true)]
[COMServerAssociation(AssociationType.Directory)]
public class MyContextMenuExtension : SharpContextMenu
{
Do not use the same GUID as shown here but create your own unique one in Visual Studio via Menu Tools > Create GUID. Use a different GUID for every shell extension you write.
Then recompile the dll and install and register it again (using regasm or the SharpShell Server Manager tool.
Then create a text file named "registry.reg" with the following content (use your own specific GUID). Instead of "MyContextMenuExtension" specify the name of your extension.
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\Directory\Background\shellex\ContextMenuHandlers\MyContextMenuExtension]
#="{A75AFD0D-4A63-41E3-AAAA-AD08A574B8B0}"
Install the "registry.reg" file by double clicking. Your extension should now be active when you open the context menu for a folder background or the Desktop.
Instead of using the *.reg file, you can also make the changes manually using registry editor or if you have an installer instruct the installer to make those registry changes.
Modify SharpShell to handle the registration of the extension for the folder background for you
Make the following changes to the SharpShell source code:
In the file AssociationType.cs add a new enum value to the AssociationType enumeration:
/// <summary>
/// Create an association to the unknown files class.
/// </summary>
UnknownFiles,
/// <summary>
/// Create an association to the background of folders and the desktop
/// </summary>
DirectoryBackground
In the file ServerRegistrationManager.cs add a new private string constant:
/// <summary>
/// The 'directory' special class.
/// </summary>
private const string SpecialClass_Directory = #"Directory";
/// <summary>
/// The 'directory background' special class.
/// </summary>
private const string SpecialClass_DirectoryBackground = #"Directory\Background";
Also in the file ServerRegistrationManager.cs in the method CreateClassNamesForAssociations in the big switch statement add a new case like this:
case AssociationType.Directory:
// Return the directory class.
return new[] { SpecialClass_Directory };
case AssociationType.DirectoryBackground:
// Return the directory background class.
return new[] { SpecialClass_DirectoryBackground };
Finally you only have to tell your own extension class to use this new enumeration value:
[Guid("A75AFD0D-4A63-41E3-AAAA-AD08A574B8B0")]
[ComVisible(true)]
[COMServerAssociation(AssociationType.Directory)]
[COMServerAssociation(AssociationType.DirectoryBackground)]
public class MyContextMenuExtension : SharpContextMenu
{
I have used SharpShell some time ago, forgotten it since then (because it works flawlessly). I have used it on files and folders, so your question intrigued me. A little research on the tool led me to the answer No(unfortunately).
The binding is done through the com server associations on SharpShell. And by looking at the documentation of the com server associations I am not seeing the way to your desired functionality.
PS: I encourage you to leave a comment on the documentation page, or contact directly with the author of the library. He seems to be really helpful(I've contacted him before).