Friday, May 23, 2008

iPhone Screenshots

The iPhone has a built in screen shot app.

Activating the screenshot function is a matter of editing ~/Library/Preferences/com.apple.springboard.plist so that it contains a Boolean value called SBMobileScreenshotr that is set to true (notice the strange r at the end, not a typo!). I used sftp, then the Property List Editor on the Mac, then sftp'ed it back. Then restart the SpringBoard.

Use the following super-secret key combination: Hold down the Home key and toggle the mute switch. Your screen flashes white, a screen shot appears on your camera roll.

I pasted some of this info directly from here and here. Very handy!


Tuesday, May 20, 2008

Sending an SMS to the WM5 Emulator

If you need to send a TXT message to your WM5 emulator, then, from the emulator, send a message to the number 0010001. Immediately after the TXT is sent, it will be sent back to your phone as if it came from that number.

For other handy emulator numbers, check here. Here are some of the special numbers mentioned:


Voice numbers: 7272470, 7272979, 7272620, 7272917, 7272688, 7272263, 7274390, 7274388, 7274386, and 7274389

Data numbers: 7272455, 7272931, 727343, and 7273432

Always busy: 7272024

Never answer: 7272773

Emergency: 911, 112, 08, 999

SMS: 0010001 0010002

Tuesday, May 13, 2008

Creating a COM Proxy in .Net

I've got a VB6 COM component that is being used by lots of other applications: VB6 apps, Word Add-ins, Outlook add-ins, Outlook forms, VBScript libraries etc. I want to upgrade this to .Net so that (a) we are reducing our dependence on VB6, and (b) we can start using some of the cool new .net capabilities and (c) new .Net components can talk to this component via standard .Net methods rather than using COM.

The idea is to break this component into two separate .Net components. The first will be a proxy component which implements all of the original methods and properties from the VB6 component, and implements the same COM interface, so it can be swapped in for the old component. It won't do any work, but instead will invoke methods on the second component to do the work. The second .Net component will be a .Net assembly written in the proper .Net fashion that does all of the work that the old VB6 DLL used to do. New .Net applications can make calls directly into the second component and by-pass the COM interface.

So how do we create this COM facade? The way I ended up doing it was to extract the type library from the VB6 component, generate a .Net assembly that defines the interfaces in CLR metadata, and then created a .Net assembly to override the interfaces.

vb6-to-net-typelibrary-dll.jpg

The steps for this are:

1. On a machine which has your VB6 COM component registered and Visual Studio 6.0, fire up the OLEView tool.

2. Find your VB6 component. I looked under "Automation Objects" for the ProgId which is the "MyComp.ClassA" you use when you do a CreateObject("MyComp.ClassA") in VB6.

3. Select "Object-View Type Information" to display the "ITypeLib Viewer". Your IDL is in the right-hand pane.

4. Save the IDL by clicking the save button. You now have a "MyComp.IDL" file.

5. Fire up the VS2008 command prompt and navigate to your IDL file.

6. Type "MIDL MyComp.IDL" to generate a type library. I needed to reorder some of the things in the IDL to get it working. You will now have a "MyComp.TLB" file.

7. Create your .Net assembly by typing "tlbimp MyComp.Tlb /out:MyCompTlbAssembly.dll". This will generate a "MyCompTlbAssembly.dll" file. This is a .Net assembly that defines your interface. Now we need to override it and implement our new code.

8. Create a new .Net Class project. I called mine "MyCompProxyNET".

9. Add a reference to your recently create "MyCompTlbAssembly.dll" by using "Project-Add Reference" and then going to the "Browse" tab and finding your dll.

10. Create a class for the first class from your VB6 component that you want to override, eg ClassA. I called my class "ClassAProxy".

11. Add an import of the System.Runtime.InteropServices, set your prog id to match the original VB6 prog id, and implement your interface. So you have something like this:


using System;
using System.Runtime.InteropServices;

namespace MyCompProxyNET
{
[ProgId("MyComp.ClassA")]
public class ClassAProxy : MyCompTlbAssembly.ClassA
{
}
}


12. Now implement the interface for this class. VS2008 will generate stubs for you if you right click the interface ("MyCompTlbAssembly.ClassA" in this case) and choose "Implment Interface". Nice!!

13. Almost there, now we just have to make this COM visible. Under "project-Properties-Application-Assembly Information", check the "Make assembly COM-Visible" box, and "OK". Under "Project-Properties-Build" check the "Register for COM Interop" box.

14. Build your solution. Your .Net assembly is now the registered component for that ProgId. You can verify this by looking up the ProgId in the registry under HKEY_CLASSES_ROOT and following the Clsid to the HKEY_CLASSES_ROOT/CLSID/{your clsid}. You can see that the name of the .Net component will be displayed in the "InProcServer32" key. Previously your VB6 dll would have shown up in here.

Run one of your apps that used the old VB6 component and you should get a nice "The method or operation is not implemented" error message. This error is thrown by the .Net stubs you created in step 12. Just put some real code in your stubs and away you go!