How do you read a registry value using a custom msbuild task? - msbuild

I'm creating an MSBuild task that will read the registry for a specific registry key. If I write the same line of code (see below) in a console application, it returns the expected result, but when it is within the MSBuild task, it returns nothing.
Return Registry.GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer\Setup\", "SQLPath", Nothing)
I would expect the above code to return Nothing if the key/value pair doesn't exist, and return the value if it does exist. I am getting Nothing when the MSBuild task gets executed. Is there some attribute that I need to apply to the Execute function of the MSBuild task to tell it that it needs to read the registry?
EDIT:
Here is what is being executed from the MSBuild task:
Return Registry.GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\MSSQLServer\Setup\", "SQLPath", Nothing)
I beleive this to be caused by the Registry Redirector on my Vista x64 machine running MSBuild in 32bit. Is there any way that you can tell the custom MSBuild task (written in VB .Net) to look in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer\Setup\ then only if nothing exists there then look in HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\MSSQLServer\Setup\?
Thank you,
Scott Blue

You can read the registry directly from MSBuild, without a custom task, like this:
$(registry:Hive\MyKey\MySubKey#Value)
E.g.,
$(registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer\Setup\)
You said that you're looking to do this from a custom task, so this may not apply, but I'm posting it in case it helps.

Our msbuild script runs from an x86 Visual Studio Command Prompt. It does not read the 64 bit registry when using this syntax. It there a different syntax which would allow the x86 to read the 64 bit registry?

How about using VB's If() ternary function?
Function GetSqlPathFromReg() As Object
Return If(Registry.GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer\Setup\", "SQLPath", Nothing), _
Registry.GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\MSSQLServer\Setup\", "SQLPath", Nothing))
End Function
Assuming you have an Output() property:
Private _sqlPath As String
<Output()> _
Public ReadOnly Property SqlPath() As String
Get
Return _sqlPath
End Get
End Property
Then all you have to do is calling it from the Execute() method:
_sqlPath = GetSqlPathFromReg().ToString()

Related

Using a function without returning a value visual basic

I'm making a batch development kit in visual basic and i need to be able to call a function that sets textboxes to a saved files text. How do i do this without returning? I tried this, and it lets me run the program, but gives me a warning, not an error. How do i go about doing this? Here is my little function design. P.S. I recently switched back to VB from Java and i'm so used to doing public void. Thanks in advance!
Public Function loadProject()
End Function
You want a Sub, which is the equivalent to the Java void method.
Public Sub LoadProject()
End Sub
It's not a bad Idea to just have a function that returns a value like a success statement just in case you need it. A call to the function doesn't have to accept or use the return value from the function.
You could even build a class with two values - txtpreviousvalue and txtnewvalue
Have your function return that type and fill an instance of the type with the respective values.
One day, if you need it, you'll have it.
P.S. I'm only posting this as an answer because the good answer posted by sstan is not marked as the answer; You should probably do that.

MVVM Light RaisePropertyChanged Error

I followed examples of RaisePropertyChanged for the MVVM Light libraries in a WPF application. This seems like it should be valid. Event the code hints seem to think so. But when I build, Visual Studio gives me an error and then highlights RaisePropertyChanged with light blue squiggleys. Anyone seen this issue? Is there something obvious I'm missing?
Private _selectedServerInstance As String
Property SelectedServerInstance As String
Get
Return _selectedServerInstance
End Get
Set(value As String)
_selectedServerInstance = value
RaisePropertyChanged(Function() Me.SelectedServerInstance) //Error on build
End Set
End Property
' Looks ok until I build. The Error for each line with RaisePropertyChanged using a lambda property selector is:
' error BC30518: Overload resolution failed because no accessible 'RaisePropertyChanged' can be called with these arguments:
for RaisePropertyChanged:
References required to assemblies 'System.Linq.Expressions', 'System.Runtime', 'System.ObjectModel'.
Check References in your project.
System.Runtime and System.ObjectModel are not in the list of references to choose. Is this because they are 'facade' references, and rarely get used except in the crazy case of mvvm-light?

Declaring a variable for use in a Build Process

I am using a custom build process template and I am trying to declare a variable that can be used to populate the default in an argument, but I'm having some problems and I think it's simply because I don't quite understand how XAML and the build process use variables.
For ease of explanation (because our build process is terribly complex) here is what I'm looking at:
Process Begin
Run On Agent
Initialize Variables
If RunTests = True Then
Establish a Connection to SQL
Run SQL
Run Tests
Email User with Results
Else
<Do Other Things>
End If
Finish Build
Process End
I'm trying to use the XAML editor built in to VS2012 (although I'm open to switching if there's a better IDE, I have to add a lot of stuff to this template). So I'll click on the Run On Agent node and click on the Variables section to create a variable called SQLServername. This variable is supposed to be populated by the SqlServerHostName argument that is part of the Build Definition. So SQLServername's default value is SqlServerHostName. No problem there, I think.
However, I then try to add a new argument: ConnectionString which defaults to "Server=" & SQLServername & ";database=master;integrated security=sspi", and the compiler error:
SQLServername is not declared
Occurs. I'm sure I am misunderstanding variables and how they're used within this thing, but what should I be looking for?
It turns out that I was misunderstanding the scope of the variable declaration. I simply left the ConnectionString as a string that the user can modify, which works for our purposes.

Calling PythonFunction's from a VB application hosting Iron Python

I'm a C++ programming who was tapped to write a small application in Visual Basic. The application hosts an IronPython runtime and I am attempting to define some function in python and then call them from VB. I have written a simple test function in python
def test():
print "Test was Called"
Then I use the iron python to create a ScriptSource from the python file. I am able to look up the "test" variable through object operations but I can not figure out how to call the object that. For example (in VB):
pyScope = engine.CreateScope()
pySource = engine.CreateSourceFromFile("C:\Some\File\path\test.py")
pySource.Execute(pyScope)
' Now I expect the function test() to be defined in pyScope
Dim tmp as Object
pyScope.TryGetVariable("test", tmp)
At this point in my code tmp is defined as an object of type PythonFunction. I can't figure out how to call this function.
tmp()
Is not valid VB syntax. I've gotten this far, now how do I perform this seemingly simple task?
Edit: By calling
pyEngine.Operations.Invoke(tmp)
I am able to call the function and I see the expected output at stdout. I am still under the impression that there is some function-pointer-like type that I can cast objects of type PythonFunction to which will let me invoke temp directly without calling to the Python engine.
Not sure this will work, but try casting it to an Action type:
DirectCast(tmp, Action)()
Based on the comment, try this:
engine.ObjectOperations.Invoke(tmp, Nothing)
VB in .NET 4 should have the same dynamic support as C#. According to http://msdn.microsoft.com/en-us/library/ee461504.aspx#Y5108 (near the bottom), you should be able to do:
Dim tmp As Object = scope.GetVariable("test")
... which is what you're already doing, so make sure you're targeting .NET 4.
If that doesn't work you should be able to cast it with the generic version of GetVariable:
Dim tmp As Action = scope.GetVariable(Of Action)("test")
Finally, you already discovered Invoke on ObjectOperations.
(You may need to tweak the syntax, since I don't know VB.)

Adding a keyword to VB.net? ("Exists" vs "IsNot Nothing")

IsNot Nothing is very common, but it's a double negative =o
I'd like to use Exists instead. Is there someway I can add a keyword to my VB vocab?
For now, I wrote an extension that adds _Exists() as a property to each object. I use this frequently, but I'd still prefer an actual keyword.
<HideModuleName()>
Public Module CustomExtensions
''' <summary>
''' Returns <c>True</c> if [object] is not <c>Nothing</c>; otherwise <c>False</c>.
''' </summary>
<System.Runtime.CompilerServices.Extension()>
Public Function _Exists(obj As Object) As Boolean
Return obj IsNot Nothing
End Function
End Module
I use Visual Studio 2010 exclusively, so if I could trick VS into converting my custom phraseology into the standard syntax, that'd work for me.
Thanks!
This answer isn’t very helpful but here goes: currently, you cannot do this.
Future versions of VS (particularly when they release their compiler service internals and make them extensible) could allow it – although I actually doubt that they will allow new keywords to be added, as this isn’t in the interest of a compiler vendor who wants to ensure an ecosystem of compatible code.