The following C# code shows how to use WMI to query printers information, set and get default printer.
public bool SetDefaultPrinter()
{
System.Management.ManagementObjectSearcher search =
default(System.Management.ManagementObjectSearcher);
System.Management.ManagementObjectCollection results =
default(System.Management.ManagementObjectCollection);
System.Management.ManagementObject printer =
default(System.Management.ManagementObject);
search =
new System.Management.ManagementObjectSearcher("select * from win32_printer");
results = search.Get();
//Get Default Printer
System.Management.ManagementObject defaultPrinter = null;
foreach (System.Management.ManagementObject foundPrinter in results)
{
System.Management.PropertyDataCollection
propertyDataCollection = foundPrinter.Properties;
if ((bool)foundPrinter["Default"]) // DEFAULT PRINTER
{
System.Diagnostics.Debug.WriteLine(foundPrinter["Name"]);
System.Diagnostics.Debug.WriteLine(foundPrinter["Location"]);
}
}
//Sets new default Printer
foreach (System.Management.ManagementObject foundPrinter in results)
{
System.Diagnostics.Debug.Print(foundPrinter["Name"].ToString());
if (foundPrinter["Name"].Equals("PDFCreator"))
{
System.Management.ManagementBaseObject outParams =
foundPrinter.InvokeMethod("SetDefaultPrinter", null, null);
if (outParams == null)
System.Diagnostics.Debug.WriteLine("Unable to set default printer");
Int32 retVal = (int)(uint)outParams.Properties["ReturnValue"].Value;
if (retVal == 0)
return true;
else
return false;
}
}
return false;
}
Complex applications are difficult too debug. You might have lots of components, some exposed
thru COM, some managed, some called from an ASP page, some used from a VB6 application that instanciates
a ServicedComponent.
And this complex applications will use databases. And one complex bug to track in applications
is when you have Connection Leaks.
Connection leaks are those situations where the application is not releasing connections to the ConnectionPool.
How can you detect the problems and their origins? One possibility could be use ADO.NET
and ODBC tracing (but that is for another post).
Now I will show an easier approach. Use extension methods!!!
What? you would say, what do extension methods have to do with this?
Well you can use an extension method to intercept all database connection. The way we do this is the following:
First create an extension method like:
public static class DBTrace
{
private static string LogDBTrace = @"C:\DBTrace.txt";
/// <summary>
///
/// </summary>
/// <param name="conn"></param>
public static void OpenWithTrace(this DbConnection conn)
{
conn.ConnectionString = NewConnectionstring(conn.ConnectionString);
#if DBTrace
File.AppendAllText(LogDBTrace,
"Opening connection [" + conn.ConnectionString + "] " +
new System.Diagnostics.StackTrace().ToString());
#endif
conn.Open();
}
/// <summary>
///
/// </summary>
/// <param name="factory"></param>
/// <returns></returns>
public static DbConnection CreateConnectionWithTrace(this DbProviderFactory factory)
{
#if DBTrace
File.AppendAllText(LogDBTrace, "Creating connection " +
new System.Diagnostics.StackTrace().ToString());
#endif
return factory.CreateConnection();
}
public static string NewConnectionstring(String connectionString)
{
#if ConnectionPoolOff
if (!connectionString.Contains("Pooling="))
{
if (connectionString.EndsWith(";"))
{
connectionString += "Pooling=false;";
}
else
{
connectionString += ";Pooling=false;";
}
}
return connectionString;
#else
return connectionString;
#endif
}
}
This will allow you to use compilation directives like: ConnectionPoolOff, and DBTrace which will
help you to turn on and off the database tracing and connection pooling in order to be able to detect connection leaks.
Second,
Look for any calls to Connection.Open() and change them to Connection.OpenWithTrace()
(A simple Find and Replace or regular expression should work).
This is a simple mechanism to implement database connection tracing.
This is an useful script taken from: http://dbaforums.org/oracle/index.php?showtopic=16834 which provides a list of the currently
open sessions.
To track if you application is having problems releasing connection you can open the SQLPlusW and run this script
a couple of times while you exercise your application.
set line 150;
ttitle "dbname Database|UNIX/Oracle Sessions";
set heading off;
select 'Sessions on database '||substr(name,1,8) from v$database;
set heading on;
select
substr(a.spid,1,9) pid,
substr(b.sid,1,5) sid,
substr(b.serial#,1,5) ser#,
substr(b.machine,1,20) computer,
substr(b.username,1,10) username,
-- b.server,
substr(b.osuser,1,8) os_user,
substr(b.program,1,30) program
from v$session b, v$process a
where
b.paddr = a.addr
and type='USER'
order by spid;
ttitle off;
spool off;
This will provide an output like:
There is a little problem with my mango :(
Every time I try to add a reference to a Web Service I end up with an empty Reference.cs.
Sad. The bug has already being sent to MS see: https://connect.microsoft.com/VisualStudio/feedback/details/624612/add-service-reference-service-proxy-class-gen-tool-bug
The workaround:
Use the SlSvcUtil.exe that can be found at:
C:\Program Files\Microsoft SDKs\Windows Phone\v7.1\Tools
Just call it with like:
SlSvcUtil.exe http://localhost:50002/DBServices.svc?wsdl
NOTE: For some reason I have found that the 7.1 version of the tool crashes with a StackOverflow.
If it happens to you just use the 7.0 version
I had a hard time trying to get some diagnostics from a RoleEntryPoint.
I was doing some setup in this entry point and getting some errors.
So I tought, mmmm: this is a Task for the super Azure DiagnosticMonitor.
And I added a bunch of Trace statements and waited to get some output in my WADLogsTables,
but NOTHING!!! ZERO NILCH! NADA!!
What happenned!!!
I took me a while to get to it. So
This is the things. I had to do.
1. First add a file called WaIISHost.exe.config
2. Add the Azure Diagnostics Trace Listener
<?xml version="1.0"?>
<configuration>
<system.diagnostics>
<trace>
<listeners>
<add name="AzureDiagnostics" type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<filter type="" />
</add>
</listeners>
</trace>
</system.diagnostics>
</configuration>
3. And very very important, you must go to Copy to Output Directory property for this file and set it to Copy Always.
4. And another thing that you need is a lot of patience. The Diagnostics infraestructure takes a while.
So you add a Thread.Sleep after the Start call
DiagnosticMonitor.Start(storageAccount, configuration);
Thread.Sleep(10000);
5. After you do that you will be able to collect some information from the WADLogsTables
If for some reason you have to use VC++ Express and you have projects that use ATL,
you will get annoying error messages like:
LINK : fatal error LNK1104: cannot open file 'atlthunk.lib'
Just follow the steps in this post and you well be ready to go:
http://www.quantcode.com/modules/smartfaq/faq.php?faqid=99
Well I was trying to create a VM Role for Azure and I got this error from my Hyper-V machine.
After some tests I hit my head and got to a clear conclusion: Silly me how could have I missed it.
The problem was I set up the VM with more memory that the available in Hyper-V, so
I changed this setting and my VM just worked!!
If I was not able to transfer any sense of sarcasm, I think that this is really hard to understand error message.
I was playing around with dumpbin trying to figure out some problems with a 32-bit dll and in order to make
dumpbin run from the command line I just copied the mspdb100.dll file to
C:\Program Files\Microsoft Visual Studio 10.0\VC\bin>
Something simple right! No harm can be gotten from something like that? WRONG!!!
After that some of my C++ project stop compiling with the annoying message: Program database manager mismatch!!.
Luckily I remembered copying that file, so I just gave it a try, and guest what? Everything works fine now.
Well I’m posting it just a reminder that for VS C++ you must put attention on all the details
How do you write a Windows Service in VB6?
Althought this is not a recommend practice due to the stability issues and VB6 support, if for
any reason you need to do this I provide a guide of how to do that in VB6 and how do the same thing
in VB.NET and C#.
Using the NTSVC.ocx
This is an OCX implement by Mauricio Ordonez some time ago.
It is very simple to use. You just drop it on a form and add some code to your VB6.
Example: VB6 Form with the NTSVC.ocx control
Private Sub Form_Load()
Me.Visible = False
Dim strDisplayName As String
On Error GoTo Err_Load
strDisplayName = NTService1.DisplayName
If Command = "-install" Then
' Enable interaction with desktop.
NTService1.Interactive = True
If NTService1.Install Then
MsgBox strDisplayName & " installed successfully"
Else
MsgBox strDisplayName & " failed to install"
End If
End
ElseIf Command = "-uninstall" Then
If NTService1.Uninstall Then
MsgBox strDisplayName & " uninstalled successfully"
Else
MsgBox strDisplayName & " failed to uninstall"
End If
End
ElseIf Command = "-debug" Then
NTService1.Debug = True
ElseIf Command <> "" Then
MsgBox "Invalid command option"
End
End If
' Connect service to Win32 services controller.
NTService1.StartService
Err_Load:
' Error starting service
End Sub
Private Sub Timer1_Timer()
MsgBox "hola"
End Sub
NOTE: Remember that VB6 is not a supported platform and that even if it is true
that you can still run VB6 code in Windows Vista and Windows 7 MS does not support this
platform anymore.
How can I convert my VB6 service to .NET?
To create a Windows Service in VB.NET follow this steps.
1. First you need to create a Windows Service Project:
a. Open Visual Studio 2010
b. Go to the File\New\Project….
c. Select the Windows Service Template
d. And you just put your code in the OnStart method:
Public Class Service1
Protected Overrides Sub OnStart(ByVal args() As String)
' Add code here to start your service. This method should set things
' in motion so your service can do its work.
ExecuteWindowsServiceCode()
End Sub
Protected Overrides Sub OnStop()
' Add code here to perform any tear-down necessary to stop your service.
End Sub
Private Sub ExecuteWindowsServiceCode()
'TODO Add Some Code
End Sub
End Class
e. Another typical thing to do in Windows Service is to add a Timer Control, you you can have
your windows service performs some actions every number of seconds. To do that, drag a
Timer Control on your Service component, execute the Start method of the timer control on the OnStart method and
handle the Tick event:
Public Class Service1
Protected Overrides Sub OnStart(ByVal args() As String)
' Add code here to start your service. This method should set things
' in motion so your service can do its work.
Timer1.Start()
ExecuteWindowsServiceCode()
End Sub
Protected Overrides Sub OnStop()
' Add code here to perform any tear-down necessary to stop your service.
Timer1.Stop()
End Sub
Private Sub ExecuteWindowsServiceCode()
'TODO Add Some Code
End Sub
Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
MsgBox("Viva la vida Loca!")
End Sub
End Class
If you need to recover some of your code from your VB6 project, download our Visual Basic Conversion Tool VBUC tool.
How do I Install my Windows Service?
In general you just need to use the command line utility installutil.exe for more details see this other post.
When you start moving applications to the Silverlight and the Cloud
it wont belong for you to start wondering if you can move your applications
to be able to work on mobile devices, and it is a natural thing to wonder.
One of the best features of Artinsoft conversion tools from VB6 and other languages
to .NET is that we generate very clean code, it is not a runtime as much as possible
it is plain vanilla .NET code. And that allows us to easily move to other .NET platforms
using our evolution framework.
Moving a VB6 or Winforms applications will require some libraries not currently present in WP7,
one of those libraries are the one to read from a Config file. If you are in need of this functionaly
Alex Yakhnin has provided a good port of the Mobility Configuration block that will allow you to do something as simple as:
/ Get section
ApplicationSettingsSection section = (ApplicationSettingsSection)ConfigurationManager.GetSection("ApplicationSettings");
// Display values
this.textBlock1.Text = section.AppSettings["localServer"].Value;
this.textBlock2.Text = section.AppSettings["remoteServer"].Value;
Jejeje. Well if you are a phone developer, either an iOS guy who is thinking on offering
his/her apps in the MS Marketplace or just someone with a great interest in Windows Phone
then you should know what mango is.
Mango is a new update for the Windows Phone, and it will mean a lot for developers,
because if you already liked WP7 you will love MANGO.
VIDEO LINK
Mango means HTML5 yes!
Mango means Multitasking!
Mango means Hands-free messaging, did you ever
wanted to send SMS without using your fingers, now you can!
I don’t think is mentioned in this video but Mango is also SQLCE a great alternative
for Android and iPhone developers who were using sqllite.
In iOS SQLite is part of the Core Services and you can easily integrate it in your applications.
Even in Android you have access to this platform.
If you don’t know what SQ Lite this is a quote from www.sqlite.org:
“SQLite is a software library that implements a self-contained, serverless, zero-configuration,transactional SQL database engine. SQLite is the most widely deployed SQL database engine in the world. The source code for SQLite is in the public domain.“
So what is your equivalent in WP7. Well if you want to wait the Mango Release of Windows Phone 7
will include Sql Server Compact Edition, so that will provide a fairly good and supported platform, but
in the meantime I recommend that you check http://wp7sqlite.codeplex.com/
For VB6 applications it is common to rely on OS or Kernel API Calls. Some of those APIs might
need you to send data back and for the native API.
Marshalling in .NET can be complicated and bothersome. I have published several posts about
interop. But it usually depends on adding several marshalling attributes and even tricks specially for
fixed strings.
So I decided to provide a more a simpler approach for conversion. In this approach you just need to things:
1. Your VB6 types or structs will be mapped to .NET classes
2. All VB6 type or struct fields will be mapped to public fields
3. An attribute must be used on those fields to indicate the field length, for arrays or strings.
4. Extension methods .AsString() .SetFromString and .GetClassLength will handle all the complexities of setting the struct fields.
Let’s see an example:
Type EmployeeRecord
FirstName As String * 5
LastName As String * 5
End Type
That vb6 type will be mapped in .NET following this approach to:
public class EmployeeRecord
{
[FixedLength(5)]
public string FirstName = "Mau";
[FixedLength(5)]
public string LastName = "Rojas";
}
You can then simple use that class in .NET
var emp = new EmployeeRecord {FirstName="Mauricio",LastName="Rojas"} ;
var str = emp.AsString();
//This str value will be "MauriRojas" the helper extension methods
// .AsString and .SetFromString will handle setting the internal class fields
All that is very good but how is this used in Marshalling?? Well very simple. Let’s say you have a Dll called foo.dll
with a function foo that receives an EmployeeRecord:
[DllImport("foo.dll")]
public static extern int foo(IntPtr Struct);
Then if you want to call that function you will do something like:
var emp = new EmployeeRecord { FirstName="Ann",LastName="Smith"};
string str = emp.AsString();
var ptr = IntPtr.Zero;
ptr = Marshal.StringToBSTR(str);
//or
ptr = Marshal.StringToHGlobalAnsi(str);
//or
ptr = Marshal.StringToHGlobalAuto(str);
//or
ptr = Marshal.StringToHGlobalUni(str);
//And call the native function
foo(ptr);
If the function modifies the structure and you want to reflect those changes then you will do something like:
str = Marshal.PtrToStringAnsi(ptr,typeof(EmployeeRecord).GetClassLength())
emp.SetFromString(str);
This solution can also be applied for more complex structures. For example:
public class EmployeeRecord
{
[FixedLength(5)]
public string FirstName = "Mau";
[FixedLength(5)]
public string LastName = "Rojas";
}
public class Record1
{
public int field1;
[FixedLength(10)]
public string field2 = "";
public EmployeeRecord rec = new EmployeeRecord();
}
public class GeneralInfo
{
public int field1;
[ArrayLength(5)]
[FixedLength(2)]
public String[] countrycodes = { "cr","es","mx","pa","ni"};
[FixedLength(2)]
public EmployeeRecord[] employees;
}
If you want to try it out this is the link to the CODE
A common doubt when using you want to use Azure Connect is which platforms does it support.
Remember that in order to establish a VPN between your On-Premises computer and a Web/Worker Role
you need to install a client pieces of software.
But which are the supported platforms.
Normally what you can do is just download it and then if you get something like
”Not a valid Win32 application” it means that it is not supported.
From the MSDN site (http://msdn.microsoft.com/en-us/library/gg508836.aspx in the Prerequisites section ) it is stated that:
Windows Azure Connect supported platforms:
Windows 2003 and Windows XP are not supported.
It is supported in Windows Vista, Windows 7, Windows 2008 and Windows 2008 R2
If you were in VB6 HelpContextID will be familiar for you (http://msdn.microsoft.com/en-us/library/aa267690(v=vs.60).aspx). In those sweet VB6 days all you had to do was:
Private Sub Form_Load ()
App.HelpFile = "VB.HLP"
Frame1.HelpContextID = 21004
Text1.HelpContextID = 21001
Form1.HelpContextID = 21005
End Sub
And each time you pressed the F1 button your application will have opened the .hlp file and show you the Help Topic corresponding to that ID. After migration from VB6 to WinForms Help you now have the HelpProvider.SetHelpKeyword http://msdn.microsoft.com/en-us/library/system.windows.forms.helpprovider.sethelpkeyword.aspx And you had to do something like:
internal System.Windows.Forms.HelpProvider HelpProvider1;
...
HelpProvider1.HelpNamespace = "sample.chm";
HelpProvider1.SetHelpKeyword(TextBox1, "1007.html");
HelpProvider1.SetHelpNavigator(TextBox1, HelpNavigator.Topic);
HelpProvider1.SetHelpKeyword(ListBox1, "1006.html");
HelpProvider1.SetHelpNavigator(ListBox1, HelpNavigator.Topic);
And all that seems nice. But, what can you do when you cross over to SilverlightjQuery15205164761650376022_1357918518660? Well, in general there are several systems that allow you to author your help files in html or convert your .hlp or .chm files to html, but how do you link your components to that help system in order to provide context-sensitive help???? Ok. So one of the possible solutions is very very simple. In general, the solution that I will show in this post is this: 1) First implement an attached property for adding a HelpKeyword to Silverlight components 2) Set the helpkeyword in the desired components 3) Provide logic that will open the appropiate help file. Ok. So let's implement a Silverlight Attached property. An attached propery is like adding a new property to your controls. This new attached property will be called Helpkeyword
using System;
using System.Windows.Shapes;
namespace System.Windows.Controls
{
public class HelpProvider
{
public static readonly DependencyProperty HelpKeyword =
DependencyProperty.RegisterAttached("HelpKeyword", typeof(string), typeof(HelpProvider), new PropertyMetadata(null));
public static void SetHelpKeyword(UIElement element, string keyword)
{
element.SetValue(HelpKeyword, keyword);
}
public static string GetHelpKeyword(UIElement element)
{
return (string)element.GetValue(HelpKeyword);
}
}
}
Ok. So once we have the attached property we have to use it, and set it on the code: To set it on the code we must add a namespace:
<UserControl x:Class="SilverlightApplication.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
...
xmlns:help="clr-namespace:System.Windows.Controls"
mc:Ignorable="d"
....>
And apply the attribute to components
<Button help:HelpProvider.HelpKeyword="helpforbutton1" Content="Button" ... />
<TextBox help:HelpProvider.HelpKeyword="helpfortext1" Height="47" ... />
So that almost everything, now we just need to trigger the appropiate logic, to do that we will add a KeyUp handler to the top most element, in this example a grid. NOTE: if Silverlight is running on the browser F1 is not an option. I just used F2 here as an example.
<Grid x:Name="LayoutRoot" Background="White" Height="205" KeyUp="LayoutRoot_KeyUp">
<Button help:HelpProvider.HelpKeyword="helpforbutton1" ... />
<TextBox help:HelpProvider.HelpKeyword="helpfortext1" ... />
</Grid>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Browser;
namespace SilverlightApplication
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
private void LayoutRoot_KeyUp(object sender, KeyEventArgs e)
{
//check for the specific key. For now use F2 as the Help Shortcut
if (e.Key==Key.F2) {
var uielement = FocusManager.GetFocusedElement() as UIElement;
if (uielement!=null)
{
var keyword = HelpProvider.GetHelpKeyword(uielement);
var host = HtmlPage.Document.DocumentUri.Host;
var port = HtmlPage.Document.DocumentUri.Port;
var url = string.Format("http://{0}:{1}/help/{2}.html", host,port,keyword);
HtmlPage.Window.Navigate(new Uri(url),"_blank");
}
} // else ignore the keystroke
}
}
}
This property can be used on the IDE:
On code
var uielement = FocusManager.GetFocusedElement() as UIElement;
if (uielement!=null) {
var keyword = HelpProvider.GetHelpKeyword(uielement);
}
This is an image of the application running.
And you can download the code from: CODE
If you have any questions or would like more info on Silverlight migration check www.silverlightmigration.com
On a previous post I was describing how some basic Objective-C elements were mapped to C#.
In particular I showed how the @interface and @implementation definitions are to be mapped in .Net, including basic properties.
In this post I will show a little about how methods are migrated.
There are several things to analyze when moving Objective-C code to C# it might be simple but can be a complicated
task. Objective-C is a language created under the inspiration of SmallTalk. And in Smalltalk programmer do not think of
method calls but instead of message sending and that is something to keep in mind when doing this migration.
Also all methods are virtual and even if there are access restriction in Objective-C I will map those methods to
public for simplicity sake.
In the previous post we had:
FIRSTFIRST
Fraction.h
#import <Foundation/NSObject.h>
@interface Fraction: NSObject {
int numerator;
int denominator;
}
-(void) print;
-(void) setNumerator: (int) n;
-(void) setDenominator: (int) d;
-(int) numerator;
-(int) denominator;
@end
And
Fraction.m
#import "Fraction.h"
#import <stdio.h>
@implementation Fraction
-(void) print {
printf( "%i/%i", numerator, denominator );
}
-(void) setNumerator: (int) n {
numerator = n;
}
-(void) setDenominator: (int) d {
denominator = d;
}
-(int) denominator {
return denominator;
}
-(int) numerator {
return numerator;
}
@end
And that example shows properties and methods with no parameter. OK. Now lets just focus on methods with 0, 1 and more parameters.
MethodsExample.h
#import <Foundation/NSObject.h>
@interface MethodsExample: NSObject {
}
-(void) print;
-(int) multiplyByTwo: (int) n ;
-(void) multiplyTwoNumers: (int) a andSecondNumber: b;
@end
MethodsExample.m
#import "MethodsExample.h"
#import <stdio.h>
@implementation MethodsExample
-(void) print {
printf( "Hola mundo\n" );
}
-(int) multiplyByTwo: (int) n {
return n * 2;
}
-(int) multiplyTwoNumbers: (int) a andSecondNumber (int) b {
return a * b;
}
@end
And calling those functions will be:
#import <stdio.h>
#import "MethodsExample.h"
int main( int argc, const char *argv[] ) {
// create a new instance
MethodsExample *m = [[MethodsExample alloc] init];
[m print];
int result;
result = [m multiplyByTwo: 1];
result = [m multiplyTwoNumbers: 1 andSecondNumber: 5];
// free memory
[m release];
return 0;
}
This little example shows some of the particularities of Objective-C.
In Objetive-C all parameters starting from the second parameter can have
what is called a label and labels are similar to namedParameter. Ok lets go ahead and map that class.
using System;
public class MethodsExample
{
public virtual print() {
Console.WriteLine("Hola mundo\n");
}
public virtual int multiplyByTwo(int n)
{
return n * 2;
}
//AproachOne
public virtual int multiplyTwoNumber(int a,int andSecondNumber)
{
return a * andSecondNumber;
}
//AproachTwo
//I just renamed as multiplyTwoNumber2 to avoid compilation errors.
//The idea is that you will choose one of the two aproaches
//or define a criteria for the instances where aproach one should be used
//instead of approach two
public virtual int multiplyTwoNumber(int a,int andSecondNumber)
{
int n = andSecondNumber;
//This aproach will be better if you have a lot of code in the method
//and you prefer to keep the original arg name
return a * n;
}
}
So the thing here is what to use as the parameter name, the label or the argument name.
In the example you can see the two approaches in the multiplyTwoNumbers case.
And calling the methods is simple and the named parameters syntax can be exploited.
using System;
public static class Program
{
public static int Main(string[] argv ) {
// create a new instance
var m = new MethodsExample();
m.print();
int result;
result = m.multiplyByTwo(1);
result = m.multiplyTwoNumbers(1,andSecondNumber: 5); //using named parameters
// free memory
m.release();
return 0;
}
}
REMEMBER: This is just a glimpse of some mapping concepts from Objective-C to C#.
There are many subtle details in this kind of migration and is my belief that only
an automated tool is able to process all those details in an effectively and more error-free
than a manual approach. For example in objective-c if m is null that will not cause any error if you
do something like [m print] and in C# that will throw an error. However a migration tool could determine
if the variable will have a value before its use and avoid adding unnecessary if (m!=null) statements.
We will examine this and other details in following posts. I hope this little examples give you enough information
for playing around migrating some Objective-C code. And if it gets too complicated just send me an email!!!
This problem appear to web because I opened some forms with
Expression Web 4.0 and it seems to have modified my project files.
I finally found that to solve it all I have to do is to:
1. Open the .csproj with a text editor
2. Look for the ToolsVersion an change it from 4.0 to 3.5
And that’s all.
The actual Isolated Storage location is fixed but depends on the operating system where the Silverlight application is running:
From: http://msdn.microsoft.com/en-us/library/3ak841sy.aspx#isolated_storage_locations
Operating system | Location in file system |
Windows 98, Windows Me - user profiles not enabled | Roaming-enabled stores = <SYSTEMROOT>\Application Data Non Roaming stores = WINDOWS\Local Settings\Application Data |
Windows 98, Windows Me - user profiles enabled | Roaming-enabled stores = <SYSTEMROOT>\Profiles\<user>\Application Data Non roaming stores = Windows\Local Settings\Application Data |
Windows NT 4.0 | <SYSTEMROOT>\Profiles\<user>\Application Data |
Windows NT 4.0 - Service Pack 4 | Roaming-enabled stores = <SYSTEMROOT>\Profiles\<user>\Application Data Non roaming stores = <SYSTEMROOT>\Profiles\<user>\Local Settings\Application Data |
Windows 2000, Windows XP, Windows Server 2003 - upgrade from Windows NT 4.0 | Roaming-enabled stores = <SYSTEMROOT>\Profiles\<user>\Application Data Non roaming stores = <SYSTEMROOT>\Profiles\<user>\Local Settings\Application Data |
Windows 2000 - clean installation (and upgrades from Windows 98 and Windows NT 3.51) | Roaming-enabled stores = <SYSTEMDRIVE>\Documents and Settings\<user>\Application Data Non roaming stores = <SYSTEMDRIVE>\Documents and Settings\<user>\Local Settings\Application Data |
Windows XP, Windows Server 2003 - clean installation (and upgrades from Windows 2000 and Windows 98) | Roaming-enabled stores = <SYSTEMDRIVE>\Documents and Settings\<user>\Application Data Non roaming stores = <SYSTEMDRIVE>\Documents and Settings\<user>\Local Settings\Application Data |
Windows Vista | Roaming-enabled stores = <SYSTEMDRIVE>\Users\<user>\AppData\Roaming Non roaming stores = <SYSTEMDRIVE>\Users\<user>\AppData\Local |
The amount of data that you can put on the isolated storage is limited by the UserQuota property.
By default an application has 1MB of storage space.
(see http://msdn.microsoft.com/en-us/library/system.io.isolatedstorage.isolatedstoragefile.increasequotato(VS.95).aspx)
If more space is needed the user can call the method increaseQuotaTo() that will allow prompting the user for permision to increase the amount of storage.
This will show a prompt dialog like:
To define policies I recommed looked at the Group Policy settings page
http://www.microsoft.com/GetSilverlight/resources/documentation/grouppolicysettings.aspx#isolated-storage and we might see more details about that in another post.
Some people ofter forget about this (even me ) So that;’s why I’m posting about this.
In my work (at Artinsoft) we are currently performing a lot of Winforms and VB6
migration to Silverlight. And a common problem is “What can I do with the user settings!!!”.
In VB6 you had your INI files and in Winforms you probably used something like the App settings.
But when you move to Silverlight what can you do!.
You need a set of initial values and you probably wont want to “burn” those inicial values in your XAP file.
It would be nicer if those values can just be set in the Web.Config file.
So a common way to solve this, is develop a simple helper class. This helper class will use a service that will
collect your initial ini files or appsettings values and store them in your Isolated Storage.
You can even use some kind of basic cryptography if you feel that your date is sensitive.
And then you can use the helpful IsolatedStorageSettings class. For example see this code,
that I borrowed from this post: http://wildermuth.com/2008/10/21/Using_Isolated_Storage_Settings_in_Silverlight_2
const string FAVCOLORNAME = "favoriteColor";
public Color? FavoriteColor
{
get
{
if (IsolatedStorageSettings.ApplicationSettings[FAVCOLORNAME] != null)
{
Color? colorSetting = IsolatedStorageSettings.ApplicationSettings[FAVCOLORNAME] as Color?;
if (colorSetting != null) return colorSetting;
}
// If we can't find a favorite color, return a null color
return new Color?();
}
set
{
IsolatedStorageSettings.ApplicationSettings[FAVCOLORNAME] = value;
}
}
As you can see is very easy to save and recover simple settings from the Silverlight Isolated Storage
Specially if you are working with Silverlight and Azure you will end up in situation where you would
like to redirect your WCF Endpoint dinamically ( I don’t think you can guess the GUID that Azure will generate
for your staging enviroment).
Out of the box the silverlight behaviour is that the WCF endpoints are hardcoded in a config file called
ServicesClient.config embedded in the .xap file.
This can be problematic at least for Azure deployment infraestructure because you can deploy to different sites:
Staging and Production.
Each of this Web Sites will have differente URLs.For example phonebook.cloudapp.net or asdf-asdf-asdf-dasxxx.cloudapp.net
So an easy workaround is:
In WCF when a channel is created in code you can specify the endpoint,
so we only need to created different endpoints depending of the site where the the .xap file was download.
The proposed changes will be:
For example if you create services in your App.xaml.cs method Application_Startup
Then you can change your code for something like:
string url = "http://" + HtmlPage.Document.DocumentUri.Host + "/MyService.svc";
EndpointAddress endpoint = new EndpointAddress(url);
var service = new MyService(new ChannelFactory<IMyService>("*").CreateChannel(endpoint)));
This will allow you to just deploy your application to either Staging or Production environment
in Azure with no more code or config file changes.