Thursday, January 28, 2021

Opening Files as Administrator in Notepad

The Problem

 So you merrily double click a text file in Explorer and make sure heart-felt changes and then hit CTRL+S. Done. Maybe not. Instead, Notepad prompts for a new file, asks you to save it in Documents, or just denies the request altogether.



Windows, why, dost thou torture me?

Well, we know Windows does a good job these days of protecting us from such vile predators as ourselves but it can be frustrating. That said, we owe a lot to the annoying, but protective, User Account Control. 

A Quick Solution

You may have already tried creating a shortcut to notepad that has "Run as Administrator" enabled. This does allow you to drag files from Explorer onto this shortcut to launch Notepad as admin. This is an okay solution but my monitor is 43" and dragging is an inexact science that is prone to mishap.

My Preferred Solution: Send to > Notepad as Admin

You remember Send To, right? That handy, dandy context submenu allowing to send a file to a zip, e-mail destination, or even fax? But how do I set that up? Well, it just so happens I had to implement send to fax back in the "aughts" and implementing items in Send To is a well thought out breeze in my opinion.

Step 1: Notepad shortcut

We'll need that shortcut you probably already created to run Notepad as admin. Haven't done it yet? Alright. We can cover that. There are many ways to get that shortcut. Perhaps the easiest is to:
  1. Go to the Windows menu.
  2. Type notepad.
  3. Right click Notepad in the search results.
  4. Select Open file location.
  5. Copy the Notepad shortcut to your desktop (careful not to move it).


Step 2: Change the shortcut to Run as admin

If you don't know how to do this yet, here's a way:
  1. Right click the Notepad shortcut.
  2. Select Properties from the menu.
  3. On the Shortcut tab, choose the button labelled Advanced....
  4. On the Advanced Properties dialog, check Run as administrator.

Step 3: Copy the shortcut to the Send to folder

There's a Send to folder? Yes, there is. Don't know how to get there? It's pretty easy these days:
  1. Go to the Run prompt  (Windows Key + R).
  2. Type shell:sendto
  3. Now move or copy your shortcut from the desktop to the Send To folder.

Step 4: (Optional) Rename your shortcut

I didn't think Send to > Notepad was enough information, so I renamed my shortcut to Notepad as Admin.

Try it out: Right click a file, choose Send To, and then your shortcut.




Wednesday, January 21, 2015

European Countries Want a Bigger Slice of Each App

Ever wonder how much your friendly neighborhood app developer makes? As you could imagine, at $1 a pop, not too much generally speaking.

As a developer who has had just over 2 million apps downloaded on mobile and desktop platforms, I can tell you that my specific rate of purchases among those downloads is 2%. That said, it’s pretty clear we’re already dealing with the fact that we basically give away the majority of our work. Couple that with free support for those free downloads and individual developers like myself give our time away for free as well. At this rate, as you might suspect, I have a day job.

The VAT

When I found out there were changes in the tax laws in the European Union that govern the VAT (Value Added Tax) applied to app purchases, I was surprised to see that every country was choosing to take a larger slice of the pie. Where, previously, the general rate was 15%, every country’s new, individual rate was more than that—up to as much as 27%. These changes were effective 01/01/2015.

Break Down

App stores, for the benefit of the consumer, generally make the app price the final price. That is, your chosen price point—let’s say, 99¢—is the total price including tax.

So let’s break this down. Someone buys my app for 99¢ in Sweden.
VAT takes 25¢ (99¢ * 25%)
The store takes 22¢ (74¢ * 30%)
I temporarily get 52¢ (99¢ - 25¢ - 22¢)
Later, my government takes approximately 13¢ (52¢ * 25%)

In the end, I make 39¢ per sale of a 99¢ app in Sweden. Wow. That’s worse than I thought when I set out to write this. In some other EU countries, it could be even less—though not too much.

I never expected to make a million dollars and it looks like I won’t have to worry about my expectations being shattered but the majority of the money my app generates goes to other people.

So?

So what? Where else can someone like me, on their own, create something and make it available for sale to huge numbers of people around the world? Why don’t I just increase my price in Sweden?

Sunday, July 13, 2014

digitalmason.net Hits 1 Million Windows Phone Downloads

Screenshot7Screenshot1Screenshot3

Jack of Tools Pro is a virtual tool belt for your Windows Phone. Thanks to a recent deal posted on AppDeals, Jack of Tools Pro had an exceptional Independence Day weekend that catapulted digitalmason.net’s total Windows Phone downloads to over 1 million and left Jack of Tools Pro sitting as the #1 Top Paid App on Windows Phone in the US, Spain, Germany, Italy and Canada.

“This is exciting news for any independent app developer,” said Jonathan Isabelle of digitalmason.net. “It shows that even the guy working at nights and on weekends while maintaining a day job can have success in the Windows Phone Marketplace.”

Jack of Tools Pro

Also, a recent deal for Jack of Time contributed in reaching that 1 million downloads mark as well.

Jack of Time

If you are a Windows Phone user, check out the App Deals app to find daily deals on apps. If you are a Windows Phone developer, you might want to see how AdDeals could help you.

Thursday, May 24, 2012

100 things I learned while writing Windows Phone 7 apps


This is a work in progress:

  1. Ship early, ship often.  If it's good enough to show your spouse or kids, that's version 1.0.
  2. Don't add features that take a long time to implement. Wait for someone to ask for them.
  3. Sleep deprivation seems to be cumulative.
  4. Contests are good motivation. They have deadlines.
  5. A version of your app is probably already translated into Chinese.
  6. Put money you make from your apps back into your apps.
  7. Try AppDeals.
  8. The community is a good and friendly one.
  9. Use analytics.
  10. Localize your successful apps.
  11. Have a mobile FAQ.  
  12. Have a link to your FAQ right where a user might be getting frustrated.
  13. Test your app in another Locale with different text and time formatting rules.
  14. Look for Microsoft and phone players' events in your area.  It's worth driving to your local big city.
  15. Use nice icons--especially XAML ones.
  16. Use Twitter.  
  17. Post about your apps.
  18. Read what others have found.
  19. Allow the user to create secondary tiles that go directly to useful features of your app.
  20. Kids are awesome testers.
  21. Leverage Facebook.
  22. Take an occasional break--don't work all night, every night.
  23. Use the beta feature of the App Hub.
  24. Use advertising.
  25. Think about adveristing alternatives.
  26. Combine multiple advertising approaches.
  27. Don't set Canvas.Top or Canvas.Left to large or rapidly changing values off of the surface.
  28. Use third party tools.
  29. You're going to have to put on a marketing hat at some point.  Check this out.
  30. Issuing an update is another chance to catch people's attention. Make the new feature noticeable.
  31. Leverage others' APIs.
  32. Put the language of the UI thread into your analytics.  Later choose languages to localize to based on this.
  33. Remember, the US may not be your biggest market.
  34. Search for your app (in quotes) on Google.
  35. Search for your app (in quotes) on Twitter.  Save this search.
  36. Include a feedback page with links to support, FAQ, Twitter, and Facebook.
  37. Include a link to search the marketplace for your other apps.
  38. Reply to support requests in no more than a day.
  39. The quicklier you respond, the more likely you'll get a response from them.
  40. Put your feature ideas in a list so you don't forget them.
  41. Sort your features and bug lists by priority. Do them in that order.
  42. Indie developer with a day job? You wear 4 or 5 hats in limited time--don't just think like a dev.
  43. Read your reviews. Use a tool or app that shows you reviews from all markets and translates them.
  44. Do not link to Bing Maps if you plan to publish to the Chinese Marketplace.
  45. Test in both Dark and Light themes.
  46. To make a background image work in both themes, use Opacity < 1.

Sunday, January 8, 2012

Windows Phone 7: Getting Started with Analytics

Initially, I went with PreEmptive's RTI which was great at first, although I didn't like running the tool to generate the XAP nor the restrictions of using attributes.  It was worth it though for a while.  When RTI got too latent and the freeness waned, I looked to MSAF.  I was directed to a great article to get started "Statistics for your Windows Phone application..." by Mark Monster.  This may be enough for you to get up and running.  Again, it's a great start but turned out to not be enough for me.

So what happened?
Initially, with a couple statistics being logged, everything seemed promising so I started sprinkling my version of Mark's AnalyticsTracker throughout my code mostly replacing the spots where I had used RTI.  I launched the debugger on the Emulator and....it exited.  I thought that was weird.  Since I was using the debugger, I expected any exception to break into Visual Studio.  You may have experienced this before--an exception occurs early in your program and it seems as if the debugger's not all hooked up by the time it happens.  What was a little more perplexing was that, occasionally, it would launch without issue.  This made me suspect a race condition...but with what?

The Race is on
Considering what code I had just added, I figured the AnalyticsTracker was being used before the AnalyticsService had started.  This was easy to verify by making the tracker check for the existence of the service and verify it was initialized.

So what to do about the events that occur too early?  I'm not too fond of just rearranging things until it works as it seems like a lurking issue that may show up on just the right device.  Instead, I made my AnalyticsTracker buffer the events that occur early on.

Here's the updated AnaylticsTracker class:

   /// <summary>
   /// Creates an analytics tracker which can be used to send events through the analytics provider.
   /// NOTE: Instances of this class should not be kept around and reused over time b/c initialization in
   /// the constructor may fail if it's created too soon and, if it does, events will be deferred continually.
   /// You can use it in such a scenario but only if you call <see cref="Connect"/> when <see cref="IsConnected"/> is false.
   /// </summary>
   public class AnalyticsTracker
   {
      /// <summary>
      /// Indicates whether tracking is enabled.  For debugging mostly.
      /// </summary>
      public static bool Enabled { get; set; }

      static readonly Queue<AnalyticsEvent> deferred = new Queue<AnalyticsEvent>();

      static AnalyticsTracker()
      {
         Enabled = true;
      }

      /// <summary>
      /// Creates a default instance.
      /// </summary>
      public AnalyticsTracker()
      {
         Connect();
      }

      /// <summary>
      /// [Re]attempts to connect to the analytics service.
      /// </summary>
      public void Connect()
      {
         if (!Enabled)
            return;

         // If already connected, we're good.
         if (IsConnected)
            return;

         var service = Application.Current.ApplicationLifetimeObjects.OfType<AnalyticsService>().SingleOrDefault();
         if (service != null && !service.IsStarted)
            return;

         try
         {
            CompositionInitializerEx.SatisfyImports(this);
            // Flush any premature events.
            Flush();
         }
         catch (Exception ex)
         {
            Debug.WriteLine("Error creating analytics event. Deferring. {0}", ExceptionFormatter.FormatMessage(ex));
         }
      }

      /// <summary>
      /// Indicates whether this tracker is connected to the service.
      /// </summary>
      public bool IsConnected
      {
         get { return Log != null; }
      }

      /// <summary>
      /// Import from the analytics service provider.  Do not access directly.
      /// </summary>
      [Import("Log")]
      public Action<AnalyticsEvent> Log { get; set; }

      /// <summary>
      /// Logs or defers logging of an event.
      /// </summary>
      /// <remarks>If the analytics service is not yet up, the events are queued.</remarks>
      public void Track(string category, string name, string actionValue = null)
      {
         var analyticsEvent = new AnalyticsEvent { Category = category, Name = name, ObjectName = actionValue };
         if (Log == null)
         {
            lock (deferred)
               deferred.Enqueue(analyticsEvent);
         }
         else
            Log(analyticsEvent);
      }

      /// <summary>
      /// Track an exception.
      /// </summary>
      public void Track(Exception error)
      {
         Track("Errors", ExceptionFormatter.FormatName(error), error.ToString());
      }

      /// <summary>
      /// Flush deferred events.
      /// </summary>
      void Flush()
      {
         // Check before locking unnecessarily.
         if (deferred.Count <= 0) 
            return;
         
         lock (deferred)
         {
            while (deferred.Count > 0)
               Log(deferred.Dequeue());
         }
      }
   }

Issues with XAML Approach
There is a TrackAction trigger you can use in XAML.  I didn't like how this ended up impacting the organization of my data.  If you use this approach, you might want to take a look at the data coming into your provider before settling on it especially considering localization.

Other Things to Watch Out for
The Composition namespace.  This was frustrating.  Somehow I ended up adding a reference to the wrong Composition container.  If MEF can't find your imports, keep this in mind.  I noticed they included a CompositionInitializerEx in the WebAnalytics namespace.  I'd stick with this one to be sure you're using what they're using.
Don't use localized strings.  I touched on this above.  If any of the strings you use for your analytics are localized, you might find it hard to aggregate the data disregarding language.  For example, it'd be easy enough to track the current tool your users are choosing by its name (say CurrentTool.Name) but consider using the type instead if the tool's name is localized (e.g., CurrentTool.GetType().Name or CurrentTool.ToString()).

Wrapping Up
I hope this saves you time if you have any of these issues.  There are many more things to consider once you get analytics pumping.  For example, you might want to log the language your app is launched with.  By default, there's something logged automatically but there are issues.  I'll try to cover this in a more specific post.  In the meantime, try to think ahead about what you'll want to know.


Saturday, September 24, 2011

Windows Phone 7: Using the Compass

Want to add a compass to your Windows Phone 7 app? Want to get that AR app started? Most of us are in the same boat--we want to use the compass, motion, gyro, etc. but we can't. We've installed Mango but, without manufacturer-specific drivers, we're out of luck. If you're really anxious to get started anyway, let me share what I did and the lessons learned.

My first attempt was to create a set of "watchers".  I created a CompassVirtualWatcher and a CompassSensorWatcher both derived from an abstract base class, CompassWatcher.  The Sensor watcher implemented the base class functions using the actual Mango Compass API.  The Virtual watcher used a set of values that moved relatively randomly to simulate the compass function.

Having dealt with WP7 sensor APIs before, I knew the events would likely be coming in on a different thread.  Since I implemented the watchers using Observable (Microsoft.Phone.Reactive), it was easy to leverage ObserverOnDispatcher (or so I thought) to interact with the UI during updates.

The idea proved useful.  I was able to add a compass to my "Jack of Tools" app, play with it and see it seem to function.  I even simulated variant accuracy and the need for calibration so my calibration UI would pop up.

Once convinced the app worked, I eyed the CompassSensorWatcher for probably an hour just trying to catch any issues I might not see with the virtual watcher.  This included considering the potential threading issues once again but eventually I was convinced I had done my best.

Of course, the moment it hit real hardware with a compass, it locked up.  Now what?  I knew it must be something about working with the actual hardware but just could not figure out how to test that.  I posted in several places begging for drivers, emulators, ideas, etc. to no benefit.  Hence the reason for making this post.

Finally, an epiphany:  I didn't necessarily need compass hardware to recreate my bug.  Any hardware might be enough.  That is where the FauxCompass came in (my Flux Capacitor caliber idea of the year).  I would create an object derived from SensorBase<T> that implemented compass like functionality using the Accelerometer.

Of course, this was not so simple:

  1. SensorBase has only an internal constructor so there would be no deriving from that.
  2. Compass is sealed so there would be no deriving from it either.
  3. CompassReading has a public constructor but no public property setters so there'd be no implementing anything that returned CompassReadings.
This wasn't a show stopper but it made the implementation of the FauxCompass a little less elegant.  In the end, the signature is just like the Compass but using FauxCompassReading instead.  So, to switch between the regular Compass and the Faux Compass requires changing the code in four spots:  the member declaration, the constructor call, the observable declaration, and observable target's signature.

Once in place, I ran my app, switched to the Compass view, and it locked up.  "Damn it!  Now what?!" I thought.  You're probably already there but it took me a few seconds to really get it--that's exactly what I wanted.  My FauxCompass had repeated the bug that the real compass was producing and in short time.  I used it to fix the Compass bug in minutes.

So what did the FauxCompass do?  It consumed Accelerometer readings and converted them to FauxCompassReadings.  Turning the phone on one axis, produced headings from 0 to 359; turning on another axis, varied the accuracy resulting in a CalibrationNeeded event when it hit 20.

I hope this helps someone else waste less time with their compass app.  Please let me know if it does, if it doesn't, or if you have another solution.