I am having trouble with getting access to the default C#-LanguageService in IVsExpansionClient.FormatSpan(IVsTextLines pBuffer, TextSpan[] ts). I need a Source-Instance of the current LanguageService to be able to create an EditArray for the incoming Span.
I was able to receive a COM-Object with the following code:
pBuffer.GetLanguageServiceID(out var languageServiceId);
var provider = Microsoft.VisualStudio.Shell.ServiceProvider.GlobalProvider;
var vssp = provider.GetService(typeof(IOleServiceProvider)) as IOleServiceProvider;
var iunknown = new Guid(VSConstants.IID_IUnknown.ToString());
IntPtr ptr;
if (ErrorHandler.Succeeded(vssp.QueryService(ref languageServiceId, ref iunknown, out ptr)))
{
try
{
service = Marshal.GetObjectForIUnknown(ptr);
lang = (LanguageService)service;
}
finally
{
Marshal.Release(ptr);
}
}
But the cast lang = (LanguageService)service; fails. I have no idea what type that COM-Object behind service is. So my question is, how do I get the current LanguageService of an open editor?
I have taken parts of the code from here:
https://github.com/microsoft/VSSDK-Extensibility-Samples/blob/346f5b0289e5fb8de639ba96fb10703df06cd22d/WPFDesigner_XML/WPFDesigner_XML/ViewModel.cs#L275
Thank you!
The language services implement a number of different interfaces, you'd be then trying to query it for whatever interface you want. You mentioned C#, and in our case we don't actually derive from the package framework LanguageService at all, so that cast would fail.
You may want to clarify in your question what you're trying to achieve, since that's not exactly clear to me.
Related
I am writing a Rider/ReSharper nav-from-here plugin which is supposed to determine a target type based on a symbol I am standing on using some simple rules, and finally, navigate to it.
The first part is okay, I have managed to form the FQN needed, but I am struggling with the navigation. I found this StackOverflow post, and thought I might try this approach. So I have been trying to use TypeFactory.CreateTypeByCLRName for like two hours to create an IDeclaredType instance to be able to get the IDeclaredElement using GetTypeElement() and eventually get its declarations. But the API seems to have changed and no matter what I do I cannot get my code to work.
Here is what I've got so far:
// does not work with Modules.GetModules(), either
foreach (var psiModule in solution.GetPsiServices().Modules.GetSourceModules())
{
var type = TypeFactory.CreateTypeByCLRName("MyNamespace.MyClassName", psiModule);
var typeElement = type.GetTypeElement();
if (typeElement != null)
{
MessageBox.ShowInfo(psiModule.Name); // to make sure sth is happening
break;
}
}
The weird part is, I actually see a message box - but only when the tab with MyClassName.cs is active. When it is in focus, everything is fine. When it's not or the file is closed, the class does not get resolved, type.IsResolved is false.
What am I doing wrong?
To do this, you should have a IPsiModule instance from the context where you plan to use the type you're looking for. You can get it from some syntax node you're working with via .GetPsiModule() method or via many other ways (like dataContext.GetData(PsiDataConstants.SOURCE_FILE)?.GetPsiModule().
void FindTypes(string fullTypeName, IPsiModule psiModule)
{
// access the symbol cache where all the solution types are stored
var symbolCache = psiModule.GetPsiServices().Symbols;
// get a view on that cache from specific IPsiModule, include all referenced assemblies
var symbolScope = symbolCache.GetSymbolScope(psiModule, withReferences: true, caseSensitive: true);
// or use this to search through all of the solution types
// var symbolScope = symbolCache.GetSymbolScope(LibrarySymbolScope.FULL, caseSensitive: true);
// request all the type symbols with the specified full type name
foreach (var typeElement in symbolScope.GetTypeElementsByCLRName(fullTypeName))
{
// ...
}
}
I am new to JINT, and trying to just do some basic tests to kind of learn the ropes. My first attempt was to just store some javascript in my database, load it, and execute it in a unit test. So that looks essentially like this....
[Fact]
public void can_use_jint_engine() {
using (var database = DocumentStore()) {
using (var session = database.OpenSession()) {
var source = session.Load<Statistic>("statistics/1");
// join the list of strings into a single script
var script = String.Join("\n", source.Scripting);
// this will create the script
// console.log("this is a test from jint.");
//
var engine = new Jint.Engine();
// attempt to execute the script
engine.Execute(script);
}
}
}
And it doesn't work, I get this error, which makes absolutely no sense to me, and I cannot find any documentation on.
Jint.Runtime.JavaScriptExceptionconsole is not defined at
Jint.Engine.Execute(Program program) at
Jint.Engine.Execute(String source) at
SampleProject.Installers.Instanced.__testing_installer.can_use_jint_engine()
in _testing_installer.cs: line 318
Can anyone assist in shedding some light on this? I'm pretty confused at this point.
With JavaScript there are three entities - we care about. The host (browser, your application etc), the engine (JINT in this case) and the script ("console.log(...)") in this case.
JavaScript defines a bunch of functions and object as part of the language, but console is not one of them. By convention, browsers define a console object that can be used in the manner you describe. However, since your app is not a browser (and JINT does not do this by itself), there's no console object defined in your namespace (globals).
What you need to do is add a console object that will be accessible in JINT. You can find how to do this in the docs, but here's a simple example of how to add a log function to the engine so it can be used from the JS code (example taken from github).
var engine = new Engine()
.SetValue("log", new Action<object>(Console.WriteLine))
;
engine.Execute(#"
function hello() {
log('Hello World');
};
hello();
");
I'm trying to build an out-of-process COM server in C#. I've found this example from Microsoft: http://support.microsoft.com/kb/977996
I've build it and tested with a little VBScript:
Set app = GetObject("", "CSExeCOMServer.CSSimpleObject")
WScript.Echo(app.HelloWorld())
It works, but not when I do like this (skip the first argument of GetObject):
Set app = GetObject(, "CSExeCOMServer.CSSimpleObject")
WScript.Echo(app.HelloWorld())
I don't understand the difference between this two calls. I need the second form, because I want to make my calls from an environnement where only the second way is available.
What can I change to the server in order to make this works?
Ok, as often, I've found the solution by myself. In fact:
GetObject("", "CSExeCOMServer.CSSimpleObject")
is the same thing as:
CreateObject("CSExeCOMServer.CSSimpleObject")
If you were looking for a bad designed API, I've found one (but I don't know the whole story, may be someone here can explain me why it is like this).
The problem in my case is that the Microsoft sample doesn't register an object in the ROT (Running Object Table). So the GetObject call can not find an active object. I've resolved this by creating an instance of my class after adding this method to the constructor:
public void AddToROT()
{
IRunningObjectTable rot = null;
IMoniker moniker = null;
try
{
// Get the ROT
rot = GetRunningObjectTable(0);
// Create a moniker for the graph
moniker = CreateItemMoniker("!", "{" + CLASS_ID + "}");
// Registers the graph in the running object table
cookie = rot.Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, this, moniker);
}
finally
{
if (null != moniker) Marshal.FinalReleaseComObject(moniker);
if (null != rot) Marshal.FinalReleaseComObject(rot);
}
}
I am writing a C# client for a Corba server and I am using IIOP.NET, going by the example on the following page: http://iiop-net.sourceforge.net/rmiAdderDNClient.html
I have gotten this far without errors:
// Register channel
IiopClientChannel channel = new IiopClientChannel();
ChannelServices.RegisterChannel(channel, false);
// Access COS naming context
CorbaInit init = CorbaInit.GetInit();
NamingContext context = init.GetNameService(host, port);
The variable "host" is a string with the computer name of the server and "port" is an int representing the port number. The values for these are currently used by other systems to connect to the server so I can confirm that they are correct.
However, trying to connect to the trader service yields an exception in runtime. Here is the code I use to do that:
// Looking up VB Trader
NameComponent[] names = new NameComponent[] { new NameComponent("TraderInterface") };
object obj = context.resolve(names);
And here is the error message I'm getting:
"CORBA system exception : omg.org.CORBA.INV_OBJREF, completed: Completed_No minor: 10102."
This seems to suggest an invalid object reference, but what does that mean? Is the string I am passing to the resolve method incorrectly formatted? I have tried many different names for this service as used in other systems, but I always get the same error, which makes me wonder whether I am even interpreting it correctly.
Incidentally, in my desperation, I have also attempted to obtain an object reference from the IOR, but this again throws a different exception (namely omg.org.CORBA.ORB_package.InvalidName).
OrbServices orb = OrbServices.GetSingleton();
object obj = orb.resolve_initial_references(traderIOR);
Any advice is welcome.
I was never able to reach my server with any of the above methods, however the following code is what finally got the communication working:
Hashtable props = new Hashtable();
props[IiopChannel.BIDIR_KEY] = true;
props[IiopServerChannel.PORT_KEY] = port;
// register corba services
IiopChannel channel = new IiopChannel(props);
ChannelServices.RegisterChannel(channel, false);
MyInterface obj = (MyInterface)RemotingServices.Connect(typeof(MyInterface), ior);
I'm not entirely sure why I had to use this (seemingly) unconventional way. Perhaps it is due to the lack of a naming service running on the server. Whatever the cause, I hope this helps somebody out there.
Is it possible to do this task using C#?
Global Const COMPLUS_SERVER As String = "http://myserver"
Sub Test()
Set objRDS = CreateObject("RDS.Dataspace")
Set objCLS = objRDS.CreateObject("MY_System", COMPLUS_SERVER)
Set ListNames = objCLS.LstOBSReasons("databaseserver", "databasename", 5)
End Sub
I've tried with Activator.CreateInstance(Type.GetTypeFromProgID("")); with no success, besides I would like to know in another way that I can connect to my business object.
Thanks in advance!
It should be possible, first you need to add the Microsoft Remote Data Services Library to your project's references. You will find it under the COM tab. You can then create the RDS.DataSpace class by doing:
DataSpaceClass objRDS = new RDS.DataSpaceClass();
dynamic objCLS = objRDS.CreateObject("MY_System", "http://myserver");
dynamic listNames = objCLS.LstOBSReasons("databaseserver", "databasename", 5);
The only tricky part is you might not be able to call the resulting object through the dynamic invocation (and I assume you are using C#4). If you can't you will need to also import the types for your business object. For example look at something like this for more information on implementing COM interop.