Wednesday, November 16, 2011

An old role for banks?

The credit card companies want us to spend more, so they can get higher fees. To this end they push higher credit limits and new payment technologies (e.g. near-field payment systems). This makes paying easier and self-restraint more difficult than they already are because when using a card you don't feel the same loss you do when you part with cash. And, when you have credit, you don't stop spending when you run out of money for the week/month.

Traditionally banks were guardians of wealth, helping people to save. Perhaps they can take that positive role again. Here's how:

Instead of the 40 characters of text (or whatever) is currently gathered with each transaction for placing on the statement, banks computers should gather:
  • The old one-line description, serving backwards compatibility, and as a heading.
  • A link to the retailers web site for the transaction. This will remain private if it includes an unguessable address (e.g. many random digits)
  • Lattitude and longitude of the transaction, if practicable.
  • Exact time and date of the transaction.
  • Which card (if multiple cards attached to account) was used.
  • A breakdown of the items in the transaction (e.g. petrol $50, milk $3), including classifications.
  • Details of taxes included (because this makes business expense claims easier).
Customers could also configure their cards to only accept certain transactions, or to place limit on some sorts of transactions, and not others. This is what encourages retailers to supply this data. e.g.
  • A child could be given a card that provides him a regular allowance to be spent on anything, but also allows unlimited expenditure on local buses and trains.
  • A person saving for a house can allow unlimited purchases of hard-to-control overheads (rent, insurance, petrol), while setting a budget for discretionary items.
Uses for the data:
  • Classifying expenses makes it easy for households to work out where their money is going.
  • Tax information makes it easy to reclaim tax credits from GST/VAT without separately keeping a receipt.
  • Card holders automatically retain receipts for all transactions without needing to hold onto and file paper receipts.
  • No more querying a charge, only to find that it was legitimate, with a strange (or just plain forgotten) name?
Why I might want this if I were a bank:
  • If customers want this then they'll prefer your bank.
  • This technology is inevitable in the very long term. Take first mover advantage and you'll get publicity and generate something you can sell.

Labels: , , , ,

Tuesday, August 12, 2008

Word and IOleContainer.LockContainer

I am developing an OLE link source in C# and I am having trouble determining when to automatically exit when it runs as a hidden out-of-process server. Based on the documentation I would expect to exit when the IOleContainer.LockContainer() count reaches zero. Unfortunately Word 2000 and 2002 (but not 2007) calls LockContainer(false) while it still has IOleObject.Advise() and IDataObject.DAdvise() sinks registered with my application, which it is still trying to use. Therefore I cannot use LockContainer() as the signal to shut down my hidden out-of-process COM server. How should I decide when to shut down?

(I tried waiting until all advise connections were closed, but that means my application closes and re-opens for each linked object in the Word document. I tried adding a delay before shutdown to address this problem, but Word then stopped calling LockContainer(false) as before, leaving me with a positive lock count!)

Friday, August 08, 2008

Enhanced metafile size in Word

My application creates enhanced metafiles to paste into Word. When I create a 100x100mm metafile, it appears in Word as 89x90mm. It so happens that this discrepancy is the difference between my screen's real DPI (~89 horizontal, ~90 vertical) and the notional 96DPI it reports itself as. (My metafiles use my screen as their reference device.)

The metafile contains the original size and resolution of the original output device so Word certainly has the information required. I guess it is trying to ensure that its real size on screen is reflected in print.

I have observed that Visio metafiles paste into Word at the correct size. When I examine them I can see that Visio has intentionally made them larger. (That is, ENHMETAFILEHEADER.rclBounds is exagerated.)

Word metafiles also paste correctly into Word. When I examine them I see that they have been rendered using a printer as the reference device. I am not sure whether this is a real printer, or some ideal DEVMODE that will produce nice output.

Which is the correct strategy? Can anyone help explain what Word is doing/thinking?

Thursday, May 15, 2008

OLE out-of-process server in C#

I am trying to build an out-of-process OLE server using C# (VS 2005) for linking and embedding into Office applications. Current source code is here. It works, but see README.txt.

Each "box" has a name, a comment and draws itself as a square in the available rectangle with a red cross that helps you see whether it has been truncated. The box can render itself as an embedded object, an enhanced metafile, an old-style Win16 metafile, a device-independent bitmap, and a device-dependent bitmap (HBITMAP). See BoxRenderer.cs. It includes the name of the rendering format in the top left.

The best resource I have been able to find is Kraig Brockschmidt's Inside OLE (2nd ed; ISBN 1-55615-843-2), published back in the mid-nineties. My copy did not include the original CD, but Kraig very kindly sent them to me. (They are supposed to be on the Microsoft website, but this was broken at the time of writing.) Microsoft seems to have fallen out of love with OLE and provides little useful information besides the API references.

Implementation Notes (but more in the source code comments):
  • I am only implementing existing OLE interfaces so I did not want regasm, type libraries, etc.
  • The COM layer in .Net seems to call me from a pool of threads, so I have had to be quite careful with thread safety. I would love to know if there is a way to control the threading model.
  • This is code is certainly more complicated than I had hoped, and a lot of this stuff has been pasted together from Google and guesses so please do tell me if you see anything stupid or can see a way it can be simplified. Error handling is also haphazard.
It appears that each Office application has implemented OLE separately, as each has its own distinct quirks.
Microsoft Word:
  • Well behaved, in my view.
  • Always displays ye olde Win16 metafiles.
Microsoft Excel:
  • Shows the enhanced (Win32) metafile rendering when first pasted in, but then switches to old Win16 metafiles when I resize the box. I think this is because it has called IDataObject.DAdvise requesting CF_METAFILEPICT - perhaps for backward compatibility - and thus that is what it is given we we tell its IAdviseSink of changes. Note that when it an Excel file containing a Box it asks (and shows) CF_ENHMETAFILE at all times.
  • Stretching and rescaling within Excel works fine, and will be pass on to the Box object. But, see below.
  • Resizing via BoxForm works fine, and will be reflected within Excel, so long as you have not first stretched the box using Excel. (Scaling is OK.)
  • Cross-hash lines won't go away when BoxForm is closed??? Maybe we should be putting ourselves in the running object table? (Same for Visio.)
  • Not drawing linked objects.
Microsoft PowerPoint:
  • Resizing within PowerPoint (whether stretching or scaling) is not passed on to the Box object. Instead PowerPoint scales the metafile. But, see below.
  • Resizing via BoxForm works fine, and will be reflected within PowerPoint, so long as you have not first resized the box using PowerPoint.

Tuesday, May 13, 2008

CF_BITMAP from .Net Bitmap

This is the easiest way I know to get an in-memory device-independent bitmap ready for the clipboard.

I could not use ImageFormat.MemoryBmp because it throws an exception when saved to a stream. Therefore use .bmp and strip header.

Bitmap bitmap = RenderBitmap();
MemoryStream mem = new MemoryStream();
bitmap.Save(mem, ImageFormat.Bmp);
byte[] bmp = mem.ToArray();
int offset = Marshal.SizeOf(typeof(Win32.BITMAPFILEHEADER));
IntPtr hdib = Win32.GlobalAlloc(0x0042 /*GHND*/, mem.Length - offset);
Debug.Assert(hdib != IntPtr.Zero);
IntPtr buf = Win32.GlobalLock(hdib);
Marshal.Copy(bmp, offset, buf, (int)mem.Length - offset);
Win32.GlobalUnlock(hdib);

STGMEDIUM medium = new STGMEDIUM();
medium.pUnkForRelease = null;
medium.unionmember = hdib;
medium.tymed = TYMED.TYMED_HGLOBAL;

Tuesday, July 31, 2007

Brass Mouse

I'm sick of my plastic mouse. Why doesn't somebody make a brass mouse? It would be nice if it had green felt on the bottom. Bluetooth, USB, whatever. I don't care. This one is very interesting, but I was thinking of something more along the lines of an elegant polished dome.

Thursday, May 31, 2007

How to stop a network drive disconnecting

We have a problem in our office where network drives disconnect due to inactivity but don't reconnect silently as they should. Instead they say:
An error occurred while reconnecting L: to \\server\share.
The local device name is already in use. This connection has not been restored.
Our server is OS X Tiger (i.e. Samba), and the problem only occurs on machines that are members of the domain, but where the users log in locally.

Changing deadtime in /etc/smb.conf didn't help.

I have discovered that I can reliably stop the problem occurring if I keep a file open on the server. I guess this stops the automatic disconnection, which avoids the reconnection problem. Microsoft Word will do this for you fine, but it's annoying to have that application running all the time so I've created a simple program that will lock a file for you.

To use it, download DriveLocker.exe and shove it on your network drive. Then add a shortcut to it in your Startup group in Programs. The shortcut must include the name of a file to create and lock as its parameter. e.g. the Target field in the shortcut might read:

"L:\DriveLocker.exe" L:\.DriveLocker_OCB

More on C# with Office

Sometimes the Excel or Word API provides more than one way to call a function, but only one function is visible in C#. In this case you can use InvokeMember to call the version you want. e.g.

Axes axes = (Axes)chart.GetType().InvokeMember("Axes", BindingFlags.InvokeMethod, null, chart, no_args);