Accessing functions between two .csproj files in the same application - c#

I incorporated a WLAN API given from Codeplex's Managed WiFi site into my C# project (Windows Form Application). In the API, different functions are given to retrieve various aspects of the machine's current WiFi profile. I am only interested in retrieving the RSSI strength given in the function below. I then want to take that value and stick it in a text box on my form.
(Visual Studio 2008)
In WlanAPI.cs file, the function I am interested in exists as such:
namespace NativeWifi
{
public class WlanClient
{
/// <summary>
/// Represents a Wifi network interface.
/// </summary>
public class WlanInterface
{
/// <summary>
/// Gets the RSSI.
/// </summary>
/// <value>The RSSI.</value>
/// <remarks>Not supported on Windows XP SP2.</remarks>
public int RSSI
{
get
{
return GetInterfaceInt(Wlan.WlanIntfOpcode.RSSI);
}
}
In myApp.cs I have a textbox simply named 'wifi' that will display the current RSSI.
I have included : 'using NativeWifi' in myApp.cs header, but can't seem to get the data from the RSSI function in the WlanAPI.csproj. The project builds and compiles just fine. I'm just snagged on getting the RSSI value.
In myApp.cs I have a statement to the effect of:
wifi.Text = (GetInterfaceInt(Wlan.WlanIntfOpcode.RSSI)); //app form txt_box=RSSI value
I know this is incorrect, but shows what I am trying to do.
Any ideas?
Thanks.

You should be able to solve the problems you are facing by
Adding a reference to WlanAPI.dll or WlanAPI project (if you add it to your solution)
Using code like following:
Using NativeWifi;
Class MyAPP : Form
{
public void PrintRSSI()
{
WlanClient client = new WlanClient();
var interfaces = client.Interfaces;
//Now chose an interface out of all the available interfaces. Usually there would be zero or 1 interfaces available
if(interfaces.Length > 0)
{
//Select first available interface. A more complicated logic can present the list of available interfaces to the user and and then display RSSI for the selected interface
wifi.Text = interfaces[0].RSSI.ToString();
}
}
//Other code for the class
}

Related

How to register "custom tool" with Visual Studio 2017 or Visual Studio 2019 to make it work?

Background: We have a custom tool which takes the xml input and generates the cs output. A custom tool needs to register with the Visual studio in order to make it work with that version of visual studio.
What we have done: We have done the custom tool registration with the Visual Studio 2015 which is working fine. But now the problem is with Visual Studio 2017.
Problem: So far in my research, I found until Visual Studio 2015, VS had the direct registry entries which were allowing to register the tool but from VS 2017, Microsoft has made changes in the way how registry entries are stored (a good read to understand changes in VS2017).
If I open up the VS 2017 and try to run the custom tool then I get the error
Cannot find custom tool "Tool Name" on this system.
This is obvious because custom tool is not yet registered with VS 2017 to work.
I tried to follow this guy which says to load .bin file in to the registries but he also says that it disables to launch the VS 2017. In order to launch VS, we have to unload hive. Research says, .bin file can be on different location based on type of VS installed (enterprise, pro etc.).
Has anyone done this before?
TIA
You may have to follow different approach here by creating a Visual Studio extension (VSIX), below I have explained it in detail, hope it helps.
How to create a Custom Tool or Single File Generator in Visual Studio 2017:
Prior to VS2017 creating a custom tool required implementing Interface IVsSingleFileGenerator and code to register and unregister the custom tool in the system registry, but in VS2017, Microsoft has changed entire registry structure. The change is, VS will make registry entries to a private registry so that system registry is not messed up. While previously the registry entries were made in the system registry, now they are made to
C:\Users\xyz\AppData\Local\Microsoft\VisualStudio\15.0_xx\privateregistry.bin
Visual studio 2017 also supports testing your tool directly by running it from the visual studio itself (F5), which starts another instance of Visual Studio called Visual Studio Experimental Instance and your tool can be tested in it since it makes registry entries to
C:\Users\xyz\AppData\Local\Microsoft\VisualStudio\15.0_xxExp\privateregistry.bin
Follow below steps to create a Custom Tool in VS2017:
We need to create a VSIX extension
Add new Visual Studio Package
Implement IVsSingleFileGenerator
Add the registry entry code
Compile and test the tool by running it in VS2017
Install the tool by double clicking the generated .VSIX file
We will create an extension/custom tool as an example named "CountLines" which will read a file (having Custom Tool property set to CountLines) and generate an XML file containing the number of lines in the file. e.g. <LineCount>1050</LineCount>
1. Create a VSIX extension
In order to create an extension you must have installed Visual Studio Extensibility Tools which is included as an optional feature in Visual Studio setup. If it is not installed you can also install it by modifying VS 2017 setup.
Create new VSIX (Visual Studio Extension) project by selecting
New Project -> Extensibility -> VSIX Project
give it some name like "CountLinesVSIX".
2. Add new Visual Studio Package
Once VSIX project is created, add new Visual Studio Package to it by selecting
Add -> New Item -> Extensibility -> Visual Studio Package
give it name "CountLines.cs". In CountLines.cs we need to delete existing code and replace it with our code for IVsSingleFileGenerator implementation
3. Implement IVsSingleFileGenerator
Write your custom implementation for interface IVsSingleFileGenerator, our example code is as below
using System;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using System.Text;
namespace CountLinesVSIX
{
[PackageRegistration(UseManagedResourcesOnly = true)]
[InstalledProductRegistration( "CountLines", "Generate XML with line count", "1.0")]
[Guid("202E7E8B-557E-46CB-8A1D-3024AD68F44A")]
[ComVisible(true)]
[ProvideObject(typeof(CountLines))]
[CodeGeneratorRegistration(typeof(CountLines), "CountLines", "{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}", GeneratesDesignTimeSource = true)]
public sealed class CountLines : IVsSingleFileGenerator
{
#region IVsSingleFileGenerator Members
public int DefaultExtension(out string pbstrDefaultExtension)
{
pbstrDefaultExtension = ".xml";
return pbstrDefaultExtension.Length;
}
public int Generate(string wszInputFilePath, string bstrInputFileContents,
string wszDefaultNamespace, IntPtr[] rgbOutputFileContents,
out uint pcbOutput, IVsGeneratorProgress pGenerateProgress)
{
try
{
int lineCount = bstrInputFileContents.Split('\n').Length;
byte[] bytes = Encoding.UTF8.GetBytes("<LineCount>" + lineCount.ToString() + "</LineCount>" );
int length = bytes.Length;
rgbOutputFileContents[0] = Marshal.AllocCoTaskMem(length);
Marshal.Copy(bytes, 0, rgbOutputFileContents[0], length);
pcbOutput = (uint)length;
}
catch (Exception ex)
{
pcbOutput = 0;
}
return VSConstants.S_OK;
}
#endregion
}
}
We need to provide an unique GUID for our extension such as one in above code [Guid("202E7E8B-557E-46CB-8A1D-3024AD68F44A")]. GUID can be created from VS2017 by selecting "Tools -> Create GUID". Select GUID format as Registry format. Note that GUID mentioned above code is without curly braces.
[ComVisible(true)] is required for COM Interops
[CodeGeneratorRegistration(typeof(CountLines), "CountLines", "{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}", GeneratesDesignTimeSource = true)] is a class attribute with code to register the tool. Params being GeneratorType, GeneratorName, and C# language GUID
You can also derive from "TemplatedCodeGenerator" which supports custom TextTemplate formatting, which may require some additional code implementation.
4. Add the registry entry code
Create new class file with below code, name it CodeGeneratorRegistrationAttribute.cs
using System;
using System.Globalization;
using Microsoft.VisualStudio.Shell;
namespace CountLinesVSIX
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public sealed class CodeGeneratorRegistrationAttribute : RegistrationAttribute
{
private string _contextGuid;
private Type _generatorType;
private Guid _generatorGuid;
private string _generatorName;
private string _generatorRegKeyName;
private bool _generatesDesignTimeSource = false;
private bool _generatesSharedDesignTimeSource = false;
public CodeGeneratorRegistrationAttribute(Type generatorType, string generatorName, string contextGuid)
{
if (generatorType == null)
throw new ArgumentNullException("generatorType");
if (generatorName == null)
throw new ArgumentNullException("generatorName");
if (contextGuid == null)
throw new ArgumentNullException("contextGuid");
_contextGuid = contextGuid;
_generatorType = generatorType;
_generatorName = generatorName;
_generatorRegKeyName = generatorType.Name;
_generatorGuid = generatorType.GUID;
}
/// <summary>
/// Get the generator Type
/// </summary>
public Type GeneratorType
{
get { return _generatorType; }
}
/// <summary>
/// Get the Guid representing the project type
/// </summary>
public string ContextGuid
{
get { return _contextGuid; }
}
/// <summary>
/// Get the Guid representing the generator type
/// </summary>
public Guid GeneratorGuid
{
get { return _generatorGuid; }
}
/// <summary>
/// Get or Set the GeneratesDesignTimeSource value
/// </summary>
public bool GeneratesDesignTimeSource
{
get { return _generatesDesignTimeSource; }
set { _generatesDesignTimeSource = value; }
}
/// <summary>
/// Get or Set the GeneratesSharedDesignTimeSource value
/// </summary>
public bool GeneratesSharedDesignTimeSource
{
get { return _generatesSharedDesignTimeSource; }
set { _generatesSharedDesignTimeSource = value; }
}
/// <summary>
/// Gets the Generator name
/// </summary>
public string GeneratorName
{
get { return _generatorName; }
}
/// <summary>
/// Gets the Generator reg key name under
/// </summary>
public string GeneratorRegKeyName
{
get { return _generatorRegKeyName; }
set { _generatorRegKeyName = value; }
}
/// <summary>
/// Property that gets the generator base key name
/// </summary>
private string GeneratorRegKey
{
get { return string.Format(CultureInfo.InvariantCulture, #"Generators\{0}\{1}", ContextGuid, GeneratorRegKeyName); }
}
/// <summary>
/// Called to register this attribute with the given context. The context
/// contains the location where the registration inforomation should be placed.
/// It also contains other information such as the type being registered and path information.
/// </summary>
public override void Register(RegistrationContext context)
{
using (Key childKey = context.CreateKey(GeneratorRegKey))
{
childKey.SetValue(string.Empty, GeneratorName);
childKey.SetValue("CLSID", GeneratorGuid.ToString("B"));
if (GeneratesDesignTimeSource)
childKey.SetValue("GeneratesDesignTimeSource", 1);
if (GeneratesSharedDesignTimeSource)
childKey.SetValue("GeneratesSharedDesignTimeSource", 1);
}
}
/// <summary>
/// Unregister this file extension.
/// </summary>
/// <param name="context"></param>
public override void Unregister(RegistrationContext context)
{
context.RemoveKey(GeneratorRegKey);
}
}
}
Above code will make sure your entries are made to VS private registry
5. Compile and test the tool by running it in VS2017
You may add "Install targets" in "source.extension.vsixmanifest" to ensure different VS2017 editions are supported by your extesion.
Run your tool in VS 2017 to test if it is working as expected. Once you Run the VSIX, the Visual Studio Experimental Instance will install the extension and register it in registry "C:\Users\xyz\AppData\Local\Microsoft\VisualStudio\15.0_xxExp\privateregistry.bin". You can see the installed extension by selecting "Tools -> Extensions and updates". To test the tool we will have to open a dummy project, select a file in solution explorer, go to its properties and update Custom Tool property to "CountLines". Once this is done VS will run the tool in background and generate the output, in our example it will generate a xml file under the selected file. Alternatively, once Custom Tool property is set, your can right click the file and select "Run Custom Tool"
6. Install the tool by double clicking the generated .VSIX file
Once tested successfully, try installing the VSIX which can be found at location "projectName/bin/debug". Install the VSIX by double clicking the file, follow the installation steps. Now your tool will be available for use in VS2017. Using tool is similar, right click the file on which you want to run the custom tool and select "Run Custom Tool"
In case you want to uninstall the extention, go to "Tools -> Extensions and updates -> select your extension" and click uninstall. Note that tool will not get uninstalled until VS is closed. Once closeed you will get a popup window to uninstall, select "Modify" to uninstall.
Well, during research, I got the answer of this problem.
Solution:
We have to load the the .bin file (via load hiv).
Make the changes or edit the bin to register your tool.
Unload hive.
Step#1: Load Hive.
a) Open registry (regedit). Select node HKEY_LOCAL_MACHINE.
b) Go to | File -> Load Hive
c) Select the bin file which is available at -> %LocalAppData%\ Microsoft\ VisualStudio\ 15.0_'instance_id'\privateregistry.bin.
d) Provide a key name. This will create a new key entry in HKEY_LOCAL_MACHINE with your key name.
e) You can check the .bin file at HKEY_LOCAL_MACHINE\YourKeyName\Software\Microsoft\VisualStudio\
Step#2: Edit the bin: You can now register your custom tool by following the same way as you were doing for other VS versions. Actually the only problem was to get the VS2017 keys in to the global registry and that is solved using Step#1 above.
Step#3: Unload Hive.
a) select your key under HKEY_LOCAL_MACHINE.
b) Go to | File menu
c) Unload Hive.

C# Azure and IOT Reference to type 'stream' claims to be defined in 'System.RunTime', but it could not be found

I am trying to create the sample on the following website. Its suppose to allow me to send data to Azure.
I looked up this error but I am not using the Interactive window and #r doesn't seem to be the answer. I believe that this issue prevents me from the use of my title, but I will try.
https://catalog.azureiotsuite.com/details?title=Raspberry_Pi3&source=home-page
"Reference to type 'stream' claims to be defined in 'System.RunTime', but it could not be found."
The line referring to Message gets this and the line below with the await gets it for 'Task'
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.Devices.Client;
using Windows.UI.Xaml.Controls;
namespace MyFirstIotCoreApp
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
SendDataToAzure();
}
private async Task SendDataToAzure()
{
DeviceClient deviceClient = DeviceClient.CreateFromConnectionString(<replace>, TransportType.Http1);
var text = "Hello, Windows 10!";
var msg = new Message(Encoding.UTF8.GetBytes(text));
await deviceClient.SendEventAsync(msg);
}
}
}
Good Morning;
Anytime I see an error referencing a missing item in a Framework library like
that, the first thought I have is to check the Framework version. Some functions
exist only in certain versions of the Framework as they develop new features.
Check the Framework version to see if you have selected the version that supports
that feature.

VBA object browser doesn't show class members in my .NET dll library

I'm trying to make a simple (no dependencies) .NET dll file that is accessible from VBA (MS Office). I'm using VS2015 Express, and make my dll the simplest way possible: Create a class library, add a simple class, and check the options "Make assembly COM-visible" as well as "Register for COM interop".
My C# code:
namespace TestLib {
public class Hello {
public int timestwo(int i) {
return 2 * i;
}
}
}
The library is added to the Windows registry automatically on build. I can access it from Tools --> References within the MS Office VBA editor, and the following VBA code works as expected:
Sub test()
Dim h as TestLib.Hello
MsgBox h.timestwo(2)
End Sub
Now the funny thing is: The object browser shows my class, but with no member functions! And consequently, the autocompletion feature does not work... What is going on here?
Mmm, your description of what you did is missing a few steps, it appears to me. 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.
Here's an extract from a .NET COM DLL of mine which does appear in the Object Browser and gives Intellisense when referenced for a VBA project.
[Guid("149F7A5F-7DAC-4426-8AA0-28975A2CE203")]
[ComVisible(true)]
public interface ITest
{
string testLT(string FilePath, object Args);
string RemoveListTemplates(string FilePath, object Args);
void test(string arg);
}
[Guid("D86307C2-3FFA-4518-BABC-DA5F26ABC445")]
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
public class Test : ITest
In VS, you need to add XML comments to your code:
namespace TestLib {
public class Hello {
/// <summary>
/// A method to return value * 2
/// </summary>
/// <param name="i">An integer to multiply by two</param>
public int timestwo(int i) {
return 2 * i;
}
}
}
Then make sure the tickbox for XML Documentation File is checked and ensure the XML file has the same name as your assembly. This should supply the meta data needed to populate the IntelliSense feature.

MySQL equivalent of SQLite SQLiteConnectionContext

I'm wondering what the MySQL eqivalent of the SQLiteConnectionContext class is. I need this to be able to have a common connection context for my program. I'm creating an entity based solution that will push and pull data from a MySQL database. If there is a better way to do this I'm open to that as well. Below is the SQLite version of what I am looking for.
/// <summary>
/// A ConnectionContext common for all of the Inventory project
/// </summary>
public class InventoryConnectionContext : SQLiteConnectionContext
{
public InventoryConnectionContext(bool connect = true)
: base(InventoryConnectionString, connect)
{
}
/// <summary>
/// Constructs a BudgetConnectionContext and optionally opens the connection
/// </summary>
/// <param name="connectString">Connection string that points to a connection aside from the default connection</param>
/// <param name="connect">Specifies whether or not to open the connection</param>
public InventoryConnectionContext(string connectString, bool connect = true)
: base(connectString)
{
if (connect)
Connect();
}
}
They are dynamically generated under the .edmx file in the entities project you put them in. It seems to follow this format *(nameofdb)*Entities and is an instantiable class.
To get this to generate you need to drop the EntityFrameWork, MySQL.Data, MySQL.Data.Entities NuGets and then pull your server in. You do this by clicking View->Server Explorer then right click on SharePoint Connections (may be named slightly differently) and add your server that way. You can then import all of your tables and Entities. They will show up under the .tt file and are also autogenerated instantiable classes. All of these can be worked with together by knowing that you need a context and an entity to modify a db. [context].[table].Add/Delete; An example context.test_table.Add(myEntity);.
;tldr : Add the server, it shows up under the .edmx file as a .context.tt with the classes under that.

SharedResourceDictionary: edit resource in Blend

To optimize my application, I create a SharedResourceDictionary. With this, I save about 250 mb of memory at run-time, so it works well.
My problem is in design-time, in Blend 4, I have no more access to my resource. To modify a template (witch is in my resource file), I usually right click on my control and I choose Edit Template --> Edit Current, like in this image:
I need to modify my template that way, it's 100x faster then to go in my resource file and find the good one... I have A LOT of resources...
My SharedResourceDictionary is implemented like this (found on the web):
public class SharedResourceDictionary : ResourceDictionary
{
/// <summary>
/// Internal cache of loaded dictionaries
/// </summary>
public static Dictionary<Uri, ResourceDictionary> _sharedDictionaries =
new Dictionary<Uri, ResourceDictionary>();
/// <summary>
/// Local member of the source uri
/// </summary>
private Uri _sourceUri;
/// <summary>
/// Gets or sets the uniform resource identifier (URI) to load resources from.
/// </summary>
public new Uri Source
{
get
{
if (IsInDesignMode)
return base.Source;
return _sourceUri;
}
set
{
_sourceUri = value;
if (!_sharedDictionaries.ContainsKey(value))
{
// If the dictionary is not yet loaded, load it by setting
// the source of the base class
base.Source = value;
// add it to the cache
_sharedDictionaries.Add(value, this);
}
else
{
// If the dictionary is already loaded, get it from the cache
MergedDictionaries.Add(_sharedDictionaries[value]);
}
}
}
/// <summary>
/// Check if we are in Blend to prevent error
/// </summary>
public bool IsInDesignMode
{
get
{
return
(bool)
DependencyPropertyDescriptor.FromProperty(DesignerProperties.IsInDesignModeProperty,
typeof(DependencyObject)).Metadata.DefaultValue;
}
}
}
Someone have an idea if there is a solution for this? I really want to keep this shared dictionary due to the memory improvement, but I also want to modify my resource easily...
Any clue will be appreciated. Thank you.
EDIT:
Doing this (SharedResourceDictionary), I also have an issue with static resource:
Provide value on 'System.Windows.Markup.StaticResourceHolder' threw an exception.
And when I change them to dynamic resource it works, or if I change the SharedResourceDictionary by a simple ResourceDictionary it also works. The project can compile but I cannot edit the resource without a modification as I said.
Are you compiling for .NET 4?
You might be hitting the bug where it fails to scan your ResourceDictionaries properly.
There's talk that you have to add your ResourceDictionaries at the the App.xaml level (in Application.Resources) level, and add a dummy default style.
This might not work for you as you seem to be adding your resources in your control.
http://blogs.windowsclient.net/rob_relyea/archive/2010/04/26/my-staticresource-reference-worked-differently-with-wpf-4-rc-than-it-does-with-wpf-4-rtm.aspx
Adding a Merged Dictionary to a Merged Dictionary
Trouble referencing a Resource Dictionary that contains a Merged Dictionary
http://connect.microsoft.com/VisualStudio/feedback/details/553528/defaultstylekey-style-not-found-in-inner-mergeddictionaries
Actually it is problematic to use this feature. =(
Maybe in the future things will get better, do not know if will help, but you can try a different implementation:
WPF SharedResourceDictionary
(but do not guarantee it will work)
I gave up using the SharedResourceDictionary because of problems at design time, only when the project is 100% completed I'll be back to use.

Categories

Resources