Tuesday, January 09, 2007

So this morning we got an email from PayPal:

The PayPal User Agreement states that PayPal, at its sole discretion, reserves the right to limit an account for any violation of the User Agreement, including the Acceptable Use Policy. Under the Acceptable Use Policy, PayPal may not be used to send or receive payments or donations for obscene or certain sexually oriented goods or services. The complete Acceptable Use Policy addressing Mature Audiences can be found at the following URL:

http://www.paypal.com/cgi-bin/webscr?cmd=p/gen/ua/use/index_frame-outside&ed=mature

We are hereby notifying you that, after a recent review of your account activity, it has been determined that you are in violation of PayPal's Acceptable Use Policy regarding your website:

http://www.opennetcf.org/forums/topic.asp?TOPIC_ID=8609. Therefore, your account has been permanently limited.

If you have a remaining balance, you may withdraw the funds to your bank account. Information on how to withdraw funds from your PayPal Account can be found at our Help Center.

You will need to remove all references to PayPal from your website(s) and/or auction(s). This includes not only removing PayPal as a payment option, but also the PayPal logo and/or shopping cart. We thank you in advance for your cooperation. If you have any questions, please contact the PayPal Acceptable Use Policy Department at aup@paypal.com.

Sincerely,

PayPal Acceptable Use Policy Department PayPal, an eBay Company

Right off you can tell that they didn't like something in our public Forums - a place where anyone who can enter a user name can post anything they'd like.  Offhand I don't even know what was at that topic ID as Neil deleted it once he saw this notification.  We also use the PayPal account very, very rarely - I'd guess there were probably 5 transactions in the last 12 months, so how the hell they figured some violation by "reviewing account activity" is beyond my comprehension.

So Neil replid to them that we had no activity of the sort and that the material was removed.  Shortly after that we got this:

Dear Chris Tacke,

Based on the information provided to you in our last email your account has been permanently closed. Under the Acceptable Use Policy, PayPal may not be used to send or receive payments or donations for obscene or certain sexually oriented goods or services. The complete Acceptable Use Policy addressing Mature Audiences can be found at the following URL:

http://www.paypal.com/cgi-bin/webscr?cmd=p/gen/ua/use/index_frame-outside&ed=mature

Unfortunately, we will be unable to overturn the limitation on your account. I do apologize for any inconvenience this issue may be causing you at this time.

Sincerely,
PayPal Acceptable Use Policy Department
PayPal an eBay Company

Nice.  One "infraction" of material, which we didn't post (again spammers are the lowest form of life) and which we removed, and the close the account with really no appeals process.  Not only do they charge fees way above what any other merchant provider charges and not only do they tend to monopolize eBay commerce, they evidently also employ a large number of morons. I like how they term "permanently closed" as a "limitation on your account."

How does a company like this stay in business?

1/9/2007 11:13:53 AM (Eastern Standard Time, UTC-05:00)  #    Comments [1]  | 
 Monday, January 08, 2007

There's a thread in the newsgroups where someone is trying to show a Notification before his app does some long-running process. Here's an example of how it's done.

  1. Create a WM 5.0 Windows app, then add a reference to 'Microsoft.WindowsCE.Forms'.
  2. Add a single Button to the Form and name it 'workButton'
  3. Add this to the top of the code page:

    using System.Threading;
    using Microsoft.WindowsCE.Forms;

  4. Replace the entire non-designer Form class code with this:

    public partial class Form1 : Form
    {
      public Form1()
      {
        InitializeComponent();
        workButton.Click += new System.EventHandler(workButton_Click);
      }

      delegate void EventDelegate();

      Notification m_workNotify = new Notification();
      Control m_invoker = new Control();
      EventDelegate m_workCompleteDelegate;

      private void workButton_Click(object sender, EventArgs e)
      {
        // disable the button so it can't be clicked again until work is done
        workButton.Enabled = false;
        m_workCompleteDelegate = new EventDelegate(OnWorkComplete);

        Thread workThread = new Thread(new ThreadStart(WorkProc));
        m_workNotify.Text = "I'm doing important stuff";
        m_workNotify.Caption = "Please wait...";
        m_workNotify.InitialDuration = 5;

        m_workNotify.Visible = true;

        workThread.Start();
      }

      void OnWorkComplete()
      {
        // re-enable the button
        workButton.Enabled = true;
      }

      void WorkProc()
      {
        // simulate working
        Thread.Sleep(20000);
        m_invoker.Invoke(m_workCompleteDelegate);
      }
    }

1/8/2007 2:51:27 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]  | 
 Wednesday, January 03, 2007

For those who missed it, my MSDN Webcast is now available as an on-demand download.

1/3/2007 11:27:46 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]  | 
 Tuesday, January 02, 2007

Sue Loh posted a really good blog entry on what seems to confuse many people - what exactlyis an SDK.  While her entry is really targeted toward the native developer, it's also quite applicable to a managed developer as well.

1/2/2007 8:04:38 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]  | 
 Tuesday, December 19, 2006

If you did not attend my session at last year's MEDC or at MobileConnections then you have yet another chance to learn about memory management in the Compact Framework.  Tomorrow I'll be presenting it again in an MSDN Webcast.

12/19/2006 9:31:30 PM (Eastern Standard Time, UTC-05:00)  #    Comments [1]  | 

Over the years I've noticed that questions always come in groups.  When I worked at Applied Data Systems, when a support question came in we always went the extra mile in writing up an answer because invariably we'd get at least 2 more questions on the same topic within a week.

I still see the same thing today.  Last week a fried who is pretty new to C development asked me about returning a string from a function and I went through and explained the hows and whys.  Then today I see the same question in a newsgroup.  Rather than just provide a short answer, I figure I might as well head off the repeats that are sure to come up in the coming weeks by providing a reasonable blog entry on it so I can just post a link.

So, how do we return a string from a C or C++ function anyway?  Well the short answer is "you don't."  You can, but it's rare that you ever should.  The two exceptions that come to mind are if you have an accessor that returns a globally allocated value, like a constant, or if the return is simply a copy or internal location of a parameter to the same function (strstr is an example).  Let's look at the reason why this is the case.

Let's create a method to get a string:

TCHAR *GetString()
{
}

Now the question here is memory ownership.  For the function to return some string value, a buffer must be allocated to hold that value.  So let's add that:

TCHAR *GetString()
{
    TCHAR *value = (TCHAR*)LocalAlloc(LPTR, MAX_PATH);
    _tcscpy(value, _T("Hello memory leak"));
    return value;
}

So now we allocate a buffer and return it.  This will work, fine but the caller then must know that after they use the string they must call LocalFree or they'll have a memory leak.  Now if you're tempted to say "yes, but I'll remember that" or "yes, but it's in an internal library that I'll use LocalFree in and it will never change" then you haven't been developing long.  Rule #1 is that code will *always* be changed, or copied into another project.  Rule #2 is that it is almost always someone else who will do it. Even if you're the one that does it, believe me, you won't remember this 2 years down the road until you've burned 2 weeks trying to find the memory leak that a high-profile customer is complaining about and that management has made priority 1 for the entire team.  It happens.  Do not be tempted to do this.  Ever.

Ok, so we all agree that returning a string is bad (nod your head - yes you agree).  So how do we do it?  Well we know that to prevent a leak, the caller needs to do the allocation, so can't we just pass in the buffer as a pointer?  How about this?

void GetString(TCHAR *value)
{
    _tcscpy(value, _T("Hello overrun"));
}

The value I used should be a clue as to what the problem here is.  Let's look at a use case.

TCHAR *myValue = (TCHAR*)LocalAlloc(LPTR, MAX_PATH);
GetString(myValue);

Will this work?  Sure, in this exact case it will.  But what if GetString's value is larger than MAX_PATH?  What if the caller allocated a smaller buffer, or didn't allocate one at all?  Well you'll get a buffer overrun.  If you're lucky this will manifest as a first chance exception or something that blows up spectacularly and is easy to find.  If you're not lucky (and if you're against a tight deadline, you won't be) it will cause unexpected and non-reproducible behavior that is a real bitch to debug (on a Palm I've seen this cause execution to jump right to another application with no warning - try debugging that). 

So this could be even worse than our original FUBAR (if you're unfamiliar I'll let you look it up) code.  So what's the right way to do this?  Well a good indication is how the Win32 APIs work.  Look at something like RegQueryValue.  It takes a buffer pointer and a size. And if the function is really nice, it will tell me how big the buffer should be if the caller has it too small.  Let's look at an example.

BOOL ReturnString3(TCHAR *myString, DWORD *size)
{
    DWORD requiredSize = 0;
    TCHAR *buffer = _T("Hello nice function");

    // determine how big the buffer must be
    requiredSize = _tcslen(buffer);

    if(IsBadWritePtr(myString, requiredSize)
    {
        *size = requiredSize;
        SetLastError(ERROR_INSUFFICIENT_BUFFER);
        return FALSE;
    }

    _tcscpy(myString, buffer);
    *size = _tcslen(myString);
    return TRUE;
}

Here you see that we first determine how big the buffer should be and then we check the incoming buffer against that number.  If it fails, we copy the required size to the size parameter, set a meaningful error, and return FALSE so the caller knows we failed (we can't force them to read the return, but if they don't that's just poor practice).

If the buffer is big enough, we copy in the value, set the actual size (in case they want it for something) and return TRUE.

A use case would look like this:

TCHAR *getString = NULL;
DWORD size = 0;

// this is supposed to fail - it gets the size
ReturnString3(getString, &size);

// now allocate a buffer
getString = LocalAlloc(LPTR, size);

// and get the data
BOOL success = ReturnString3(getString, &size);

So now you've seen the good, the bad and the ugly on how to return a string froma C function.  I have no illusions that me posting this will stop people from asking - even if it ends up as the number 1 result for Google.  Let's face it, you have to know enough to do the search for it to be of any use.  But hopefully, those who are in the industry because they like to learn and don't like to write crap code can either find it or be pointed to it and make good use of it.

12/19/2006 9:58:42 AM (Eastern Standard Time, UTC-05:00)  #    Comments [2]  |