Link to home
Start Free TrialLog in
Avatar of Axter
AxterFlag for United States of America

asked on

Problems with CDC::BitBlt function.

I'm having problems getting BitBlt to work right under Windows CE.
I'm using SRCAND mode with it, and the code works find under windows 95/98, but it displays as a blank area in Windows CE.
Here's the code line:
pDC->BitBlt(MaxCorners.left, MaxCorners.top, iWidth, iHeight, &dcMemory, 0, 0, SRCAND);

dcMemory variable is a black & white (mono) bitmap that I'm trying to BIT-AND with the current window.
pDC is the DC of a window.

What is a working solution for Bit-ANDing a bitmap to a CE window?
Avatar of Axter
Axter
Flag of United States of America image

ASKER

Here's the code I'm currently using:

void button_Room::DrawTransparent(void)
{
     if (m_RoomNameBitmapCStatic==NULL) return;
     CDC *pDC = AfxGetMainWnd()->GetDC();
     BITMAP bmpInfo;
     CBitmap *Tmp = CBitmap::FromHandle(m_RoomNameBitmapCStatic->GetBitmap());
     Tmp->GetBitmap(&bmpInfo);
     CDC dcMemory;
    dcMemory.CreateCompatibleDC(pDC);
     CBitmap* pOldBitmap = dcMemory.SelectObject(Tmp);
     int     iWidth = CTouchMapDlg::GetHorzFactor(bmpInfo.bmWidth);
     int     iHeight = CTouchMapDlg::GetVertFactor(bmpInfo.bmHeight);
     int prvDrawMode = pDC->SetROP2(R2_MASKPEN);
     //The following line-code only works in Win9x
     pDC->BitBlt(MaxCorners.left, MaxCorners.top, iWidth, iHeight, &dcMemory, 0, 0, SRCAND);
     /*  The following code will work on CE but it's way too slow
     for(int x=0;x<iWidth;x++)
     {
          for(int y=0;y<iHeight;y++)
          {
               COLORREF p = dcMemory.GetPixel(x, y);
               if (!p)
               {
                    pDC->SetPixel(x+MaxCorners.left,y+MaxCorners.top,0);
               }
          }
     }
     */
     dcMemory.SelectObject(pOldBitmap);
     pDC->SetROP2(prvDrawMode);
     ReleaseDC(pDC);
}
maybe the pen is the wrong color or white.  If using the pen, you should set its color before doing the BitBlt.

-- Dan
Avatar of Axter

ASKER

If that was the problem then it wouldn't work in Win9x.
Avatar of Axter

ASKER

The following text comes from the CBitmap::BitBlt Windows-CE help document.

Windows CE 1.0 only supports two bit per pixel (maximum) gray scale graphics. When performing a bit-block transfer that converts two bit-per-pixel (2bpp) to one bit-per-pixel (1bpp), Windows CE 1.0 maps the background color to white, and all other colors to black. When converting from 1bpp to 2bpp, it maps white to white and black to black, as expected.

I'm not sure what this means.  
Does this mean that the Win-CE CBitmap::BitBlt function only works with mono windows or bitmap?
Avatar of Axter

ASKER

I just realized I pasted the wrong main class above.  I meant to paste "CDC::BitBlt"
>dcMemory variable is a black & white (mono) bitmap

Is it a real monochrome bitmap? I experienced a similar problem. I had to use CreateBitmap to create a real monochrome bitmap and BitBlt the bitmap into the real monochrome bitmap and then use the real monochrome bitmap instead.
Avatar of Axter

ASKER

Yes, I'm using a real monochrome bitmap.
But the window is not monochrome, so I'm woundering if this is the problem.
Did you get this to work on a color window?
If so, could you post your code?
Yes, it is a color window (65536 colors). Sorry, I can't post my code due to the copyright.

What exactly is m_RoomNameBitmapCStatic->GetBitmap()? Can you show the content of bmpInfo after Tmp->GetBitmap(&bmpInfo)?
>>If that was the problem then it wouldn't work in Win9x.

If categorically rule out valid suggestions without trying them, you will not make progress toward a solution.  As chensu points out, there may be underlying, not clearly-apparent influences.

This is important to you isn't it? and it would be very easy for you to add a SelectObject to select a black pen, wouldn't it?  

-- Dan
Avatar of Axter

ASKER

chensu
m_RoomNameBitmapCStatic is a CStatic pointer, and GetBitmap is a member function (method) of CStatic.
I'm going to have to wait to I get on site to run a test on the bmpInfo.

DanRollins,
Sorry to sound so dismisive of your suggestion.  I can try and run a test with a black pen selected, even though I can not see how this could solve the problem because BitBlt function does not use a pen.  And if it were to use a pen, that would mean that the output would come out to the color selected.  And this is not the desired goal.
>>even though I can not see how this could solve the problem because BitBlt function does not use a pen

>>int prvDrawMode = pDC->SetROP2(R2_MASKPEN);

Axter, when you use the ROP of MASKPEN, then, well, yes BitBlt does use the pen.  Otherwise, why would I bring it into the discussion?

-- Dan

>m_RoomNameBitmapCStatic is a CStatic pointer, and GetBitmap is a member function (method) of CStatic.

Use CreateBitmap to create a monochrome bitmap and BitBlt the bitmap returned by CStatic into it.
Avatar of Axter

ASKER

DanRollins,
That line is not part of my original code, and the code works without it in Win9x.  I just added that in my last compile just to see if it would make the code work in CE.
I forgot to take it out before I copied & pasted it here.
Please ignore the following two lines:

  int prvDrawMode = pDC->SetROP2(R2_MASKPEN);
  pDC->SetROP2(prvDrawMode);
Sorry for the confusion.


chensu,
m_RoomNameBitmapCStatic is create with monochrome bitmap.  It loads a monochrome bitmap from a file.
The following line points to the monochrome bitmap:
CBitmap *Tmp = CBitmap::FromHandle(m_RoomNameBitmapCStatic->GetBitmap());

The only thing that is not monochrome is the button_Room window.

>>Is it a real monochrome bitmap? I experienced a
>> similar problem. I had to use CreateBitmap
>>to create a real monochrome bitmap and BitBlt
>>the bitmap into the real monochrome bitmap and
>> then use the real monochrome bitmap instead.

Are you saying that in your similar problem that you loaded a monocrome bitmap to a control, and then you still had to use CreateBitmap function to create a real monochrome bitmap?
>Are you saying that in your similar problem that you loaded a monocrome bitmap to a control, and then
you still had to use CreateBitmap function to create a real monochrome bitmap?

Exactly. Please try it with CreateBitmap(nWidth, nHeight, 1, 1, NULL).
Avatar of Axter

ASKER

Ok, I'll give it a shot.  I won't be able to tested it out on the CE platform until Saturday, and I'll post an update then.
Thanks
>>m_RoomNameBitmapCStatic is a CStatic pointer, and GetBitmap is a member function (method) of CStatic.

From:
http://support.microsoft.com/support/kb/articles/Q168/2/58.ASP

Resource bitmaps, usually loaded with a call to LoadBitmap(), are read- only in Windows CE. This means that if such a bitmap is selected into a memory DC, subsequent drawing functions on that DC fail.

RESOLUTION
To work around this issue, create a second bitmap with a call to CreateCompatibleBitmap() and then BitBlt() the contents of the resource bitmap onto the second bitmap. The second bitmap should be suitable for use with the drawing functions.

>>Please ignore the following two lines..

I somehow don't think I'll have any difficulty ignoring whole categories of your code in the future.

-- Dan
Avatar of Axter

ASKER

>>Resource bitmaps

I'm not using a Resource Bitmap.  As I previously stated, I'm loading the bitmap from a file.


>>I somehow don't think I'll have any difficulty
>>ignoring whole categories of your code in the future.

Hmmm.... I'm not sure what's that about.
If this is a derogatory remark, I would appreciate it if you would reframe from giving me any assistance now, nor in the future.
If this is not derogatory, then I apologize for the erroneous assumption.
What about the bitmap that is the destination of the BitBlt? -- the one in the DC?  Is it an item in a dialog box?  For instance a CStatic or CBitmapButton that originated as a resource?

-- Dan
Avatar of Axter

ASKER

The only resource bitmaps used on this application are on special dialog windows.
The main dialog and (it's children/controls), loads all the bitmaps from files.
button_Room is a child window of the main dialog.
Longshot:
Can you tell us anything about the bitmap that has been selected into the CDC that you obtain via AfxGetMainWnd()->GetDC()?  Did this get loaded from a read-only file using LoadImage(...,LR_LOADFROMFILE | LR_CREATEDIBSECTION )?

Axter says:
>> When converting from 1bpp to 2bpp, it maps white to white and black to black, as expected.

MSDN says:
"When the BitBlt function converts a monochrome bitmap to color, it sets white bits (1) to the background color and black bits (0) to the foreground color. "

It might make a difference if you set the foreground and background colors before doing the BitBlit.

Also, I can't tell from the dox exactly *when* the conversion takes place in a SRCAND operation, but it makes sense that it occurs during the output phase, so this might be happening (sorry, this will look crappy on this EE screen, but it lines up nicely when I typed it)...

11 foreground color (white color)
00 background color (black color)

11 11 11 11 11  << destination (all white)
1_ 0_ 0_ 1_ 1_  << m_RoomNameBitmapCStatic (mono)

11 01 01 11 11  << destination (white and gray)
11 11 11 11 11  << after conversion (all white)

Just a thought.

-- Dan

Hi Axter,
Are you still participating?  Have you tried the suggestions?  Do you need additional help?
-- Dan
Avatar of Axter

ASKER

Sorry, I was suppose to work on this last weekend, but my imbedded software counter part canceled and rescheduled it for this weekend.
So I should be able to test this out tomorrow (Saturday).

I'm hoping that one of the above ideas will work, but if it doesn't, I also found a CE CDIBsectionLite class that I'm going to try.
http://www.codeproject.com/ce/ 
I have been using DIBSections on Windows CE. It is more efficient than DIB.
A useful diagnostic test.  Replace the SRCAND in the BitBlt with SRCCOPY.  If that fails (even if visually incorrect -- remember, this is a testing, diagnostic procedure, not an answer) then the problem is as I suggested in my previous post.  Otherwise, that was a red-herring and I need to be punished severely.

-- Dan
Avatar of Axter

ASKER

Due to bad weather conditions, I couldn't work on this Saturday.
I'm working on it right know.

DanRollins,
>>Longshot:
>>Can you tell us anything about the bitmap that has been
>>selected into the CDC that you obtain via AfxGetMainWnd
>>()->GetDC()?
>>Did this get loaded from a read-only file using LoadImage
>>(...,LR_LOADFROMFILE | LR_CREATEDIBSECTION)?
All the images that I'm using the BitBlt function with are loaded from files.  This includes the AfxGetMainWnd.
The program is a dialog base application, and the main window displays a bitmap file.
Avatar of Axter

ASKER

chensu,
>>Exactly. Please try it with CreateBitmap(nWidth,
>>nHeight, 1, 1, NULL).

It should have occurred to me that this wouldn't work, at least not in the way I understand your suggestion.
The problem with this method is not I'm still trying to BitBlt the original Bitmap file, which is the cause of the problem.

Here's my failed attempt:
void button_Room::DrawTransparent(void)
{
     if (m_RoomNameBitmapCStatic==NULL) return;
     CDC *pDC = AfxGetMainWnd()->GetDC();
     BITMAP bmpInfo;
     CBitmap *Tmpx = CBitmap::FromHandle(m_RoomNameBitmapCStatic->GetBitmap());
     Tmpx->GetBitmap(&bmpInfo);
     CBitmap Tmp2;
     Tmp2.CreateBitmap(bmpInfo.bmWidth, bmpInfo.bmHeight, 1, 1, NULL);
     CDC dcMemory1,dcMemory2;
    dcMemory1.CreateCompatibleDC(pDC);
    dcMemory2.CreateCompatibleDC(pDC);
     CBitmap* pOldBitmap1 = dcMemory1.SelectObject(Tmpx);
     CBitmap* pOldBitmap2 = dcMemory2.SelectObject(&Tmp2);
     int     iWidth = CTouchMapDlg::GetHorzFactor(bmpInfo.bmWidth);
     int     iHeight = CTouchMapDlg::GetVertFactor(bmpInfo.bmHeight);
     dcMemory2.BitBlt(MaxCorners.left, MaxCorners.top, iWidth, iHeight, &dcMemory1, 0, 0, SRCCOPY);
     pDC->BitBlt(MaxCorners.left, MaxCorners.top, iWidth, iHeight, &dcMemory2, 0, 0, SRCAND);
     dcMemory1.SelectObject(pOldBitmap1);
     dcMemory2.SelectObject(pOldBitmap2);
     ReleaseDC(pDC);
}

Maybe I'm not understanding your suggestion, or I'm implementing it wrong.
Avatar of Axter

ASKER

DanRollins,
>>RESOLUTION
>>To work around this issue, create a second bitmap with a
>>call to CreateCompatibleBitmap() and then BitBlt()
>>the contents of the resource bitmap onto the second
>>bitmap. The second bitmap should be suitable for
>>use with the drawing functions.
The above method fails in both CE and Win9X version.

Code:

void button_Room::DrawTransparent(void)
{
     if (m_RoomNameBitmapCStatic==NULL) return;
     CDC *pDC = AfxGetMainWnd()->GetDC();
     BITMAP bmpInfo;
     CBitmap *Tmpx = CBitmap::FromHandle(m_RoomNameBitmapCStatic->GetBitmap());
     Tmpx->GetBitmap(&bmpInfo);
     CDC dcMemory1,dcMemory2;
    dcMemory1.CreateCompatibleDC(pDC);
     CBitmap* pOldBitmap1 = dcMemory1.SelectObject(Tmpx);
     CBitmap Tmp2;
    if (Tmp2.CreateCompatibleBitmap (&dcMemory1,bmpInfo.bmWidth, bmpInfo.bmHeight))
     {
          AfxMessageBox(_T("CreateCompatibleBitmap failed"));
          exit(-1);
     }
     CBitmap* pOldBitmap2 = dcMemory2.SelectObject(&Tmp2);
     int     iWidth = CTouchMapDlg::GetHorzFactor(bmpInfo.bmWidth);
     int     iHeight = CTouchMapDlg::GetVertFactor(bmpInfo.bmHeight);
     dcMemory2.BitBlt(MaxCorners.left, MaxCorners.top, iWidth, iHeight, &dcMemory1, 0, 0, SRCCOPY);
     pDC->BitBlt(MaxCorners.left, MaxCorners.top, iWidth, iHeight, &dcMemory2, 0, 0, SRCAND);
     dcMemory1.SelectObject(pOldBitmap1);
     ReleaseDC(pDC);
}
Try this:

ASSERT (iWidth);
ASSERT (iHeight);

int nRet= dcMemory2.BitBlt(0,0, iWidth, iHeight, &dcMemory1, 0, 0, SRCCOPY);

ASSERT( nRet );

nRet= pDC->BitBlt(0,0, iWidth, iHeight, &dcMemory2, 0, 0, SRCCOPY);

ASSERT( nRet );

-- Dan
P.S.  Run it in Debug mode, or replace each ASSERT(x) with

if( x ) AfxMessagebox( "BAD BAD");

-- Dan
Avatar of Axter

ASKER

It fails on CreateCompatibleBitmap, so it doesn't even get to the BitBlt function.
bmpInfo.bmWidth and bmpInfo.bmHeight are valid numbers.  I did an AfxMessageBox to show there values, and they're correct.
Avatar of Axter

ASKER

Using chensu method I don't get any errors, but the map does get displayed on the screen either.
I also added Extra error handling, but didn't catch anything.

void button_Room::DrawTransparent(void)
{
     if (m_RoomNameBitmapCStatic==NULL) return;
     CString ErrMsg;
     CDC *pDC = AfxGetMainWnd()->GetDC();
     BITMAP bmpInfo;
     CBitmap *Tmpx = CBitmap::FromHandle(m_RoomNameBitmapCStatic->GetBitmap());
     Tmpx->GetBitmap(&bmpInfo);
     CBitmap Tmp2;
     if (!Tmp2.CreateBitmap(bmpInfo.bmWidth, bmpInfo.bmHeight, 1, 1, NULL))
     {
          DebugExitMessage(_T("Error:\r\nFailed Tmp2.CreateBitmap"));
     }
     CDC dcMemory1,dcMemory2;
    dcMemory1.CreateCompatibleDC(pDC);
    dcMemory2.CreateCompatibleDC(pDC);
     CBitmap* pOldBitmap1 = dcMemory1.SelectObject(Tmpx);
     CBitmap* pOldBitmap2 = dcMemory2.SelectObject(&Tmp2);
     int     iWidth = CTouchMapDlg::GetHorzFactor(bmpInfo.bmWidth);
     int     iHeight = CTouchMapDlg::GetVertFactor(bmpInfo.bmHeight);
     if (iWidth<2 || iHeight<2)
     {
          DebugExitMessage(_T("Error:\r\nInvalide width and/or height"));
     }
     if (!dcMemory2.BitBlt(MaxCorners.left, MaxCorners.top, iWidth, iHeight, &dcMemory1, 0, 0, SRCCOPY))
     {
          DebugExitMessage(_T("Error:\r\nFailed dcMemory2.BitBlt"));
     }
     if (!pDC->BitBlt(MaxCorners.left, MaxCorners.top, iWidth, iHeight, &dcMemory2, 0, 0, SRCAND))
     {
          DebugExitMessage(_T("Error:\r\npDC->BitBlt"));
     }
     dcMemory1.SelectObject(pOldBitmap1);
     dcMemory2.SelectObject(pOldBitmap2);
     ReleaseDC(pDC);
}
>>It fails on CreateCompatibleBitmap
What does GetLastError return?

Any chance that
  MaxCorners.left, MaxCorners.top
are < 0 or so big as to be offscreen? (that's why I specified 0).

What happens (with chensu's code) if you skip the SRCAND step and simply blt using SRCCPY ?  The reason I keep asking that is unrelated to the amount of exercise that my fingers need.  It would eliminate a possible problem with gray-vs-B/W that I pointed out some time ago.  That is a likely place to focus attention because we know that the code works in the CE simulator that runs on Win98.  The main difference would be in the video device driver.

-- Dan
1. Change

int     iWidth = CTouchMapDlg::GetHorzFactor(bmpInfo.bmWidth);
int     iHeight = CTouchMapDlg::GetVertFactor(bmpInfo.bmHeight);
dcMemory2.BitBlt(MaxCorners.left, MaxCorners.top, iWidth, iHeight, &dcMemory1, 0, 0, SRCCOPY);
pDC->BitBlt(MaxCorners.left, MaxCorners.top, iWidth, iHeight, &dcMemory2, 0, 0, SRCAND);

to

dcMemory2.BitBlt(0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, &dcMemory1, 0, 0, SRCCOPY);
pDC->BitBlt(MaxCorners.left, MaxCorners.top, bmpInfo.bmWidth, bmpInfo.bmHeight, &dcMemory2, 0, 0, SRCAND);


2. Change
Tmp2.CreateCompatibleBitmap (&dcMemory1,bmpInfo.bmWidth, bmpInfo.bmHeight)

to

Tmp2.CreateCompatibleBitmap (pDC,bmpInfo.bmWidth, bmpInfo.bmHeight)
Avatar of Axter

ASKER

DanRollins,
>>Any chance that
>> MaxCorners.left, MaxCorners.top
>>are < 0 or so big as to be offscreen? (that's why I
>>specified 0).
No, I tested it out by putting some error checking code, and it didn't fail.

>>What happens (with chensu's code) if you skip the SRCAND
>>step and simply blt using SRCCPY ?  
It has no affect.  Same results.

>>CE simulator that runs on Win98.  
I don't have a CE simulator for Win98.  When I said the code runs under Win9x, I'm referring to the Windows9x version of my application.
Both projects have the same files, except for the file that has CWinApp class.
Is there a Win98 simulator available for CE?  I thought the simulator only works in Windows NT.

chensu,
Your suggested changes do look promising.
I'm going to try to get my Windows NT CE emulator working again so I can test the code out.
Other wise, I'm going to have to wait until this Saturday before I can try it out.
Avatar of Axter

ASKER

DanRollins,
>>11 foreground color (white color)
>>00 background color (black color)
>>11 11 11 11 11  << destination (all white)
>>1_ 0_ 0_ 1_ 1_  << m_RoomNameBitmapCStatic (mono)
>>11 01 01 11 11  << destination (white and gray)
>>11 11 11 11 11  << after conversion (all white)

I read this several times, and I still don't get what you're trying to say.
I understand the first three
1.destination (all white)
2.m_RoomNameBitmapCStatic (mono)
3.destination (white and gray)

But I don't understand how that should equal to the after conversion.

Let me explain a little more about the program, and unexpected results with the bitblt.

There are several button_Room windows on the main window.
By default button_Room is white, but when a external control changes certain bits, the background of the room changes colors.

When I try to use the bitblt function it always seems to make the button_Room window's area the same color as the background color.

This would seem to indicate to me that all the bits are set in m_RoomNameBitmapCStatic.
But this code works fine in Windows9x, and I'm using the same bitmap files.
ASKER CERTIFIED SOLUTION
Avatar of DanRollins
DanRollins
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Axter

ASKER

>>That may be the root of the problem.  Try setting the
>>background color to either white or black befor
>>doing the blit.  
When the system is reset, the rooms startup as white by default.
The results are the same weather the room is white, or filled in with a background color.

>>Were I debugging this, I'd use CBitmap::GetBitmapBits
>>(...) to look at the actual bits of the image data
>>between each step of the operation. I think that much
>>would make sense then.  
That's a good idea.  The only thing is that most of the m_RoomNameBitmapCStatic area is white (bits set to 1).  But I could test it out using a completely black bitmap for testing purposes, and see if GetBitmapBits return any bits that are set.

Hi Axter,
Are you still participating?  Have you tried the suggestions?  Do you need additional help?
-- Dan
Avatar of Axter

ASKER

Sorry, but I only work on this project on the weekends, and last week they had me working on some bug fixes that to priority over the bitblt problem.  I'll be working on it tomorrow, and I'll give you an update.

Thanks for your patients.
>>The results are the same weather the room is white, or filled in with a background color.

As I have shown, it is possible that all colors except black (bits 00) might be treated as white.  Just a thot to keep in mind.

-- Dan
so....?
-- Dan
Hi Axter,
Do you have an additional questions?  Do any comments need clarification?

-- Dan
Hi Axter,
Do you have an additional questions?  Do any comments need clarification?

-- Dan
Avatar of Axter

ASKER

Because I made some major modifications to the program, I had to take the original code I posted out.
I'm close to reinseting modifid version of the previously posted code.
I'm trying to get the code to mirror the previous code as much as possible, and I'm nearly done.
I'm not sure when I'll be done, but I want this question opened until I have resolved the problem, and obtained a deffinite working solution.
I thought I might get your attention :-)
-- Dan
Hi Axter,
Do you have an additional questions?  Do any comments need clarification?

-- Dan
Avatar of Axter

ASKER

The project is on hold for a month or two.

I won't be working on it until the beginning of April.

I want to leave this question open until I'm sure I have a solution.

300 points is a lot of points to give away, just to find out you didn't get a working solution.
It may be a problem with the emulator.  See:

http://support.microsoft.com/support/kb/articles/Q196/2/77.ASP

-- Dan

Avatar of Axter

ASKER

The problem is viewed in the actual hardware.

I'm not using an emulator.  I haven't been able to get the emulator to work in a while, and I haven't had time to troubleshoot the problem with the emulator.

Sorry to say, that this project is still on hold.

Everytime I want to work on it, they keep giving me something with a higher priority. :-( :-( :-(
Avatar of Axter

ASKER

Still on hold....
Hi Axter,
Do you have an additional questions?  Do any comments need clarification?

-- Dan
Avatar of Axter

ASKER

The requirement for this functionality, has been abandon.

I'm going to request the points be split between you and chensu.
Avatar of Moondancer
Moondancer

Good morning, Axter.

I have changed the value of that question from 300 to 150, the 150 points were refunded to you.  

You can now award one expert here to grade and close, and for the other expert, please post a new question in this topic area, include this link, and in the topic state Points for __expertname__ to complete the other half of this split award.

This then will retain the trail of all your questions in your history, rather than having a gap for the Points for in your history if a Moderator takes that action for you.

If you have any questions, please let us know.

It is ideal to also post the new Question Link here so the other Expert is advised.
 
Thank you.
 
Moondancer
Community Support Moderator @ Experts Exchange
Avatar of Axter

ASKER

chensu,
Please go to the following link, to get your points:
https://www.experts-exchange.com/jsp/qManageQuestion.jsp?ta=wince&qid=20254639

Avatar of Axter

ASKER

DanRollins & chensu,
Thanks for the help.
Unfortunately the part of the project that needed this code was abandon.

If I ever need this functionality for another CE project, hopefully we can pick up where we left off.

Moondancer,
Thanks for the assist.
Always happy to help where I can, Axter.  Thank you.
:)
Moondancer
Community Support Moderator @ Experts Exchange