/*
C source code compiled with Microsoft's Visual C/C++ 6.0 (with the Feb 2003 MSDN library of API's)
http://jdmcox.com/Simple Family Tree.rc
http://jdmcox.com/Simple Family Tree.h (rename it to resource.h)
http://jdmcox.com/ijl15.dll
http://jdmcox.com/ijl15.zip
add _UNICODE AND UNICODE to Project Settings C/C++ tab Category: General Preprocessor Definitions
when debugging 16-bit char data, instead of looking at &Buf[x] in the Watch window, look at &Buf[x],ma
*/
#include <windows.h>
#include <stdio.h>//for _snwprintf
#include <tchar.h>
#include "ijl.h"//put ijl15.lib in Project/Settings/Link
#include "resource.h"
#define WIN32_LEAN_AND_MEAN
#define LIGHTGRAY 0xF0F7F8
#define ROWS 100
#define COLS 1500
#define BIGCOLS 16384
#define ROWSUP 21
#define MIDROW 20
#define CHILD 1
#define MAN 2
#define WOMAN 3
#define BAD 4
#define NONE 0
#define BIRTHDAY 1
#define AGE 2
#define PHOTO 3
#define FULL 1
#define HALF 2
#define QUARTER 3
#define EIGHTH 4
#define MAXSPOUSES 6
#define EXTRAIDIVIDUALS 1000
//U-00000000 – U-0000007F: 	0xxxxxxx
//U-00000080 – U-000007FF: 	110xxxxx 10xxxxxx
//U-00000800 – U-0000FFFF: 	1110xxxx 10xxxxxx 10xxxxxx
#define MASKBITS   0x3F//00111111
#define MASKBYTE   0x80//10000000
#define MASK2BYTES 0xC0//11000000
#define MASK3BYTES 0xE0//11100000
#define MASK4BYTES 0xF0//11110000
#define MASK5BYTES 0xF8//11111000
#define MASK6BYTES 0xFC//11111100


DWORD PhotoID;
char *tempBuf, *bJpeg;
TCHAR *NamePtr;
TCHAR ThisPhotoBuf[512];
char bThisPhotoBuf[512];

TCHAR Head[] = TEXT("\
0 HEAD\r\n\
1 SOUR SIMPLE_FAMILY_TREE\r\n\
2 VERS 1.31\r\n\
1 GEDC\r\n\
2 VERS 5.5\r\n\
2 FORM LINEAGE-LINKED\r\n\
1 CHAR UTF-8\r\n");

TCHAR Trlr[] = TEXT("0 TRLR\r\n");

TCHAR szAppName[] = TEXT("Simple Family Tree 1.31");
char AppName[] = "Simple Family Tree 1.31";

char Help[] = ("\
Shows the ancestors and descendants\n\
of a highlighted individual.\n\
\n\
To highlight any individual, left-click on him/her.\n\
\n\
To display any individual's info, right-click on him/her.\n\
\n\
Backspace and Space go backward and forward\n\
thru individuals you've highlighted.\n\
\n\
Shortcut keys for Menu items are U, N, I, L, and R.\n\
\n\
To undo the last change you made, select Undo.\n\
When you make any change in Simple Family Tree,\n\
the current Gedcom data file is first backed-up,\n\
and then the change is written to it.\n\
Undo swaps the Gedcom data file and the\n\
back-up file, thus undoing the last change.\n\
\n\
To show or stop showing an individual's Age or\n\
Birthday when you move the mouse over him/her,\n\
press the A or B key.\n\
To show or stop showing which individuals have a\n\
photo linked to them, press the P key.\n\
\n\
Duplicated descendants show a small yellow square.\n\
\n\
If scrolling is possible, a horizontal and/or\n\
vertical scroll line will appear to indicate\n\
location within the family tree.\n\
\n\
To scroll, hold the Left Mouse button down\n\
while moving the Mouse,\n\
or use the mousewheel\n\
(hold the Ctrl key down for left-right),\n\
or press an Arrow Key\n\
(hold it down to scroll faster and faster).\n");

char Help2[] = ("\
Automatically saves changes in a Gedcom file\n\
(a Notepad file with a .ged extension).\n\
Other family tree programs can read that file,\n\
and Simple Family Tree can open and display the\n\
data in a Gedcom file created by other programs.\n\
\n\
Gets its display inspiration from Family Historian\n\
(my favorite full-featured family tree program).\n\
\n\
Saves the highlighted individual's Gedcom number\n\
in Simple Family Tree.ini so it can re-open\n\
at that individual.\n\
\n\
Shows ancestors and descendants of the highlighted\n\
individual (as well as up to 6 of his/her spouses).\n\
The display limits are quite large: 13 ancestor rows,\n\
80 dependant rows, and 1500 individuals in a row.\n\
\n\
The Individual's Info window can show the following:\n\
Alias, Buried, Christened, Education, Event,\n\
Graduation, Married/Divorced, [alternate] Name,\n\
Note, Occupation, and Residence.\n\
\n\
You can enter an alternate Name, info on 4 Marriages,\n\
6 Events, and enter about 6,000 words in a Note.\n\
\n\
Same-sex spouses are allowed, but only one of them\n\
can link to a child (normally an adopted child).\n\
\n\
Works with any language by using Unicode and saving\n\
Gedcom data in UTF-8 format.\n\
\n\
If you encounter any problems, please let me know!\n\
6 June 2008       {go to jdmcox.com for updates}\n\
Doug Cox   jdmcox@jdmcox.com");

TCHAR NamesDates[] = TEXT("\
A woman's last name should normally be her father's last name.\n\
\n\
Slashes around the last name are necessary so that suffix names\n\
can be entered (e.g. John /Doe/ Jr  or  Maria /Sanchez/ Gomez).\n\
Normally you wouldn't need to put the slashes in.\n\
\n\
To enter é press the Alt key while entering 130 on the keyboard number pad,\n\
or 160 for á, 161 for í, 162 for ó, 163 for ú, or 164 for ñ.\n\
\n\
Dates in family trees are usually entered in this format: 1 Jan 1999.");

TCHAR PhotoHelp[] = TEXT("\n\
The photo shown is reduced by 1/2, 1/4, or 1/8 to fit on the screen.\n\
\n\
When selecting a photo, remember that the file directory dialog box\n\
can easily be changed to show thumbnails, and can be enlarged.\n\
\n\
The link to an individual's photo is saved in a file with the current\n\
Gedcom filename with \"Photos.dta\" appended, and which will contain\n\
the individual's Gedcom number and the full filename of the photo.\n\n");

TCHAR AlternateParents[] = TEXT("\
To add a second set of parents to an individual, highlight a prospective\n\
parent (single or married), and select as a child that individual who\n\
already has one parent or one set of parents.\n\
\n\
Spouses can have the same sex, but in that case, they can't have a child.\n\
However, one of them can have a child or adopt a child.\n\
\n\
If an individual has two sets of parents (adoptive or whatever),\n\
a button labeled \"Swap Primary & Secondary Parents\" will show.");

//TCHAR SameSex[] = TEXT("Same-sex couples can't share children\nin this program because they might appear\nto be the biological parents.");

BOOL CheckBuf(void)
;
void Fill_Indiv(void)
;
void FillArray(void)
;
void FillhdcMem(void)
;
void InitializeAgain(void)
;
BOOL GetSpouse(void)
;
BOOL GetChild(void)
;
DWORD GetName(void)
;
void GetData(void)
;
int CALLBACK ListProc(HWND hwndListDlg, UINT message, WPARAM wParam, LPARAM lParam)
;
int CALLBACK IndivProc(HWND hwndIndiv, UINT message, WPARAM wParam, LPARAM lParam)
;
int CALLBACK NewIndivProc(HWND hwndNewIndiv, UINT message, WPARAM wParam, LPARAM lParam)
;
int CALLBACK NewProc(HWND hwndNew, UINT message, WPARAM wParam, LPARAM lParam)
;
int CALLBACK GEDProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
;
int CALLBACK Name2Proc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
;
int CALLBACK EventProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
;
int CALLBACK NoteProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
;
int CALLBACK MarriageProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
;
void PutFAMS(DWORD Offset)
;
void PutFAMC(DWORD Offset)
;
void PutNewFAM(int Person, DWORD Offset)
;
void PutFAM(int Person, DWORD Offset)
;
BOOL CheckifChild(DWORD Offset)
;
void GetNameinBuf(DWORD Offset, TCHAR* Name)
;
void CheckFAM(void)
;
void GetSpouseOffset(DWORD Num)
;
void SaveEdited(void)
;
void ReStart(void)
;
DWORD GetBufEnd(DWORD x)
;
int CheckRelative(DWORD saveHighlighted, DWORD savei)
;
void ParseBirthday(void)
;
void ParseBirthday2(void)
;
void ShowJpeg(void)
;
void GetPhotoFileName(void)
;
void UndoIt(void)
;
void CheckForPhotos(void)
;
void SortSiblings(void)
;
void CursorMoved(int xPos, int yPos)
;
DWORD Atoi(TCHAR*ptr)
;
void RemovePhoto(DWORD)
;
//void CheckFAMS(void)
//;
//void MergeFile(void)
//;

TCHAR PrinterName[64];
DWORD PrinterNameLen = 64;
DWORD dwSizeNeeded, dwNumItems, dwItem, dwNeeded;
HDC hDC;
HANDLE hPrinter;
LPPRINTER_INFO_5 lpInfo;
LPDEVMODE pDevMode;

int u, d, bd, date[1024], smallest, dateptr, Year, Year2;
int lines, famchild;
int Resolution, PadBytes;
int TypeOffset[6];
int DateOffset[6];
int PlacOffset[6];
int FamOffset[4];
int MarriedToOffset[4];
int MarrDateOffset[4];
int MarrPlacOffset[4];
int index, Response, oldX, newX, so, maxChars;
int BoxLeft, BoxTop, BoxRight, BoxBottom, BoxWidth, BoxHeight;
//int PhotoBoxLeft, PhotoBoxRight, PhotoBoxTop, PhotoBoxBottom;
//int FirstxPos, FirstyPos, PhotoX, PhotoY;
int Width, Height, JpegWidth, JpegHeight, IndivTop;
int Y, Z, YSpacing, cxScreen, cyScreen, xLoc, yLoc;
int xPos, yPos, xPrevious, yPrevious, Top, Left, LoopX, LoopY;
int Number = 10, endlessloop;
int hPos, hWidth, vPos, vHeight;
int Frame, TitleAndMenu, Namend;
int BirthDateLen, BirthLocLen, Death2Len, DeathLocLen;
DWORD highlighted = 0xFFFFFFFF, oldHighlighted, IndivNum = 0xFFFFFFFF, IndivNumber, highlightedNum;
DWORD ParentSpouse, spouseX, spouseof, Num, parentX, OldSize, NewSize;
DWORD v, w, x, y, z, I, X, tempY, prevy, SpaceToLeft, LeftmostSibling, FirstParent, Child, TotalParents, fileSize, fileSize2, PhotoFileSize, JpegFileSize, dwBytesRead, dwBytesWritten, wParameter, MouseLoc;
DWORD xBig, yBig;
DWORD Leftchild, Rightchild, prevRightchild, ChildLineLength, LinetoChildrenX, LinefromChildrenX, LinefromLeftchild, LinefromRightchild, Parent, Parents;
DWORD AncestorMinX, DependantMinX, LeftmostChild, LeftmostParent, LeftmostSpouse, LinefromChildX, LinetoChildX, SpouseLineLen;
DWORD ptr, marrPtr, ArrayX, ArrayY, HighlightedAncestorX, HighlightedDependantX, BufEnd;
DWORD *ArrayUp;
DWORD Array[ROWS][COLS];
DWORD indiv[ROWS];
DWORD Col[ROWS];
DWORD Spouses[MAXSPOUSES];
DWORD BirthdayNames[1024];
DWORD BirthdayDates[1024];
DWORD i, s, ws, s2, ws2, LastIndiv, RealLastIndiv, row, col, RowsUp, LastRow;
DWORD NameX, Gap, SmallestGap, NoteBegin, NoteEnd;
DWORD Fams, FamNum, FamsEnd, FamPtr, LastIndivNum, Number2, IndivOffset, DeleteOffset, NewIndivOffset, HusbNum, WifeNum;
DWORD FamS[MAXSPOUSES];
DWORD SingleParentFamNum, NoteLen;
DWORD SpouseOffset[21];
DWORD ChildOffset[21];
DWORD HusbOffset, WifeOffset, Children, SingleChildOffset, child, FamC;
DWORD g = 0, charIndex, lineIndex, firstCharIndex, lineLength, typeNameLen;
DWORD GotSpouse[MAXSPOUSES];
DWORD Backspace[512];
DWORD bs;
DWORD test, test2;
DWORD PhotoNum;
WORD Age, day, months[] = {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
BYTE *utf;

TCHAR CmdLine;
TCHAR age[4];
TCHAR CurrentDir[MAX_PATH];
TCHAR FamilyTreeIni[] = TEXT("Simple Family Tree.ini");
TCHAR IniBuf[256];
TCHAR KeyFile[] = TEXT("SimpleFamilyTree.dta");
TCHAR SimpleFamilyTreePhotos[MAX_PATH];// = "SimpleFamilyTreePhotos.dta");
TCHAR SimpleFamilyTreePhotosTxt[MAX_PATH];// = "SimpleFamilyTreePhotos.txt");
TCHAR SimpleFamilyTreePhotosBak[MAX_PATH];// = "SimpleFamilyTreePhotos.bak");
TCHAR PhotoDta[] = TEXT("Photos.dta");
TCHAR PhotoTxt[] = TEXT("Photos.txt");
TCHAR PhotoBak[] = TEXT("Photos.bak");
TCHAR Filename[MAX_PATH], Filename2[MAX_PATH], BDFilename[MAX_PATH];
TCHAR FullFilename[MAX_PATH], FullFilename2[MAX_PATH], FullBDFilename[MAX_PATH];
TCHAR PhotoFilename[MAX_PATH];
TCHAR FullPhotoFilename[MAX_PATH];
TCHAR BackupFilename[MAX_PATH];
TCHAR TempFilename[] = TEXT("zzzz.tmp");
TCHAR *Buf, *Buf2, *Birth, *Death, *BirthLoc, *DeathLoc, *Jpeg;
TCHAR temp[256];
TCHAR HighlightedName[256];
TCHAR IndivName[256];
TCHAR TitleBar[300];
TCHAR Error[512];
TCHAR Photos[] = TEXT("Photo");
TCHAR Arial[] = TEXT("Arial");
TCHAR CourierNew[] = TEXT("Courier New");
TCHAR ComicSansMS[] = TEXT("Comic Sans MS");
TCHAR ch;
TCHAR Blank[] = TEXT("\0");//"    ");
TCHAR BigNote[30000];
TCHAR MarrData[5000];
TCHAR IniShow[] = TEXT("ShowIndivInfo=");
TCHAR Loops[] = TEXT("00,000 loops");
TCHAR Additions[] = TEXT("\r\n***Additional entries***\r\nNAME: \r\n\r\nEVENT:\r\nTYPE: \r\nDATE: \r\nPLACE: \r\n\r\nEVENT:\r\nTYPE: \r\nDATE: \r\nPLACE: \r\n\r\nEVENT:\r\nTYPE: \r\nDATE: \r\nPLACE: \r\n\r\nNOTE: \r\n\r\n\r\n\r\n\r\n");
TCHAR *Ones[12] = {TEXT("ALI"),TEXT("BUR"),TEXT("CHR"),TEXT("EDU"),TEXT("EVE"),TEXT("GRA"),TEXT("NAM"),TEXT("NOT"),TEXT("OCC"),TEXT("RES"),TEXT("MAR"),TEXT("DIV")};
int TypeNameLen[12] = {10, 11, 15, 14, 10, 14, 9, 9, 14, 14, 10, 11};
TCHAR Alias[] = TEXT("\r\nALIAS:\r\n");//10
TCHAR Burial[] = TEXT("\r\nBURIED:\r\n");//11
TCHAR Christened[] = TEXT("\r\nCHRISTENED:\r\n");//15
TCHAR Education[] = TEXT("\r\nEDUCATION:\r\n");//14
TCHAR Event[] = TEXT("\r\nEVENT:\r\n");//10
TCHAR Graduated[] = TEXT("\r\nGRADUATED:\r\n");//14
TCHAR name[] = TEXT("\r\nNAME2: ");//9
//TCHAR Key[] = TEXT("\0\0\0\0\0\0\0");
TCHAR Note[] = TEXT("\r\nNOTE ");//7
TCHAR Occupation[] = TEXT("\r\nOCCUPATION: ");//14
TCHAR Residence[] = TEXT("\r\nRESIDENCE:\r\n");//14
TCHAR Married[] = TEXT("\r\nMARRIED ");//10
TCHAR Divorced[] = TEXT("\r\nDIVORCED ");//11
TCHAR Num1[24] = TEXT("0 @I");
TCHAR Num2[9] = TEXT("@ INDI\r\n");
TCHAR Name[256];
TCHAR Name1[256];
TCHAR Name2[256] = TEXT("1 NAME ");
TCHAR Name3[256] = TEXT("1 NAME ");
TCHAR Note2[30000] = TEXT("1 NOTE ");
TCHAR Sex;//M or F
TCHAR Sex2[10] = TEXT("1 SEX M\r\n");
TCHAR Birth1[9] = TEXT("1 BIRT\r\n");
TCHAR BirthDate[32] = TEXT("2 DATE ");
TCHAR BirthLoc2[256] = TEXT("2 PLAC ");
TCHAR Death1[9] = TEXT("1 DEAT\r\n");
TCHAR Death2[32] = TEXT("2 DATE ");
TCHAR DeathLoc2[256] = TEXT("2 PLAC ");
TCHAR Marr[] = TEXT("1 MARR\r\n");
TCHAR Type[256] = TEXT("2 TYPE ");
TCHAR Date[256] = TEXT("2 DATE ");
TCHAR Place[256] = TEXT("2 PLAC ");
TCHAR Even[] = TEXT("1 EVEN\r\n");
TCHAR WholeEvent[512];
TCHAR Conc[] = TEXT("\r\n2 CONC ");
TCHAR Cont[] = TEXT("2 CONT ");
TCHAR FamEntry[21] = TEXT("0 @F");
TCHAR Famend[8] = TEXT("@ FAM\r\n");
TCHAR FamHusb[10] = TEXT("1 HUSB ");
TCHAR FamWife[10] = TEXT("1 WIFE ");
TCHAR FamChil[10] = TEXT("1 CHIL ");
TCHAR NewIndiv[1140];
TCHAR Famspouse[24] = TEXT("1 FAMx @F");//x becomes C or S
TCHAR ChildsName[50];
TCHAR ChildsExtra[] = TEXT("'s Parents");
TCHAR ParentsName[50];
TCHAR And[] = TEXT(" and ");
TCHAR Nonelse[] = TEXT("no one else?");
TCHAR BirthDeath[256];
TCHAR one, two, three;
//TCHAR Line[128];
//TCHAR unknown[] = TEXT("UNKNOWN\r");
//TCHAR TheKey[] = TEXT("\0\0\0\0\0\0\0");
TCHAR PhotoDirectory[MAX_PATH];
TCHAR *PhotoBuf;
BYTE *JpegBuf;
BYTE *photo_pixel_buf;
BOOL first, firstime, duplicate, inbox, gotleftchild, notempty, parent, gotchild, nogood = FALSE, arrayfilled = FALSE, showindividual = FALSE, gotmarrdata;
BOOL preditit = FALSE, editit = FALSE, fromnewlink = FALSE, newfile, newfather = FALSE, newmother = FALSE, newspouse = FALSE, newchild = FALSE, famcfirst = TRUE;
BOOL foundspouse, notherspouse, deleetit = FALSE, unlinked = FALSE, fromrestart = FALSE, indivbox = FALSE, list = FALSE, firstphoto = TRUE;
BOOL nonote, noname, newindiv, gotit, mouseover = NONE, gotmouseover, childhasparents, photo = FALSE, fromcommandline = FALSE;
BOOL gotdate = FALSE, gotmonth, updateindiv = FALSE, dontupdateindiv, anyeditit = FALSE, undone = FALSE, firstmousemove;

struct INDIV {
	DWORD Name;
	DWORD Birth;
	DWORD BirthLoc;
	DWORD Death;
	DWORD DeathLoc;
	DWORD Num;
	DWORD Parent;
	DWORD Note;
	DWORD Child;
	DWORD X;
	DWORD Childof;
	DWORD Spouseof[MAXSPOUSES];
	DWORD Spouse;
	DWORD LeftChild;
	DWORD RightChild;
	DWORD Flags;
	WORD ArrayX;
	WORD ArrayY;
	WORD Sex;
	WORD cx;
} *Indiv;
//} Indiv [8000];

struct INDIV tempIndiv;
struct INDIV OrigIndiv[EXTRAIDIVIDUALS];
DWORD OrigIndivPtrs[EXTRAIDIVIDUALS];
DWORD oi;

HWND hwnd, hwndList, hwndInstr, hwndIndiv = NULL, hwndListDlg = NULL, hwndBirthday = NULL, hwndPhoto = NULL, hwndDescEdit;
HWND hwndName, hwndBirth, hwndAge = NULL, hwndSex, hwndDeath, hwndBirthLoc, hwndDeathLoc, hwndNote;
HANDLE hFile, hFile2, hBirthFile, hKeyFile, hPhotoFile = NULL, hPhotoFile2, hJpegFile, hFindFile, hTemp;
HDC hdc, hdcMem, hdcPrn;
HBITMAP hBitmap, hPrnBitmap;
PAINTSTRUCT ps;
RECT rect, rectMem, HighlightedRect, ListRect, dlgRect, boxRect;
SIZE Size, Size2;
HCURSOR hCursor, hDrawingCursor1, hDrawingCursor2, hWaitingCursor, hArrowCursor;
HINSTANCE hInst, hInst2;
LOGFONT lf, lf2;
HFONT hFont, hFont2;
OPENFILENAME ofn;
HBRUSH hBrush, hHighlightedBrush, hYellowBrush;
WIN32_FIND_DATA fd;
WIN32_FIND_DATAA afd;
struct _SYSTEMTIME st, *lpSystemTime = &st;
struct _FILETIME ft;
ULARGE_INTEGER li1, li2;
PRINTDLG pd;
DOCINFO di = { sizeof(DOCINFO), TEXT("USAPM"), NULL, NULL, 0 };
HGDIOBJ hObject;
HMODULE hModule;
BITMAPINFOHEADER bmih, *pbmih = &bmih, bmih2, *pbmih2 = &bmih2, bmih3, *pbmih3 = &bmih3, bmih4, *pbmih4 = &bmih4;
BITMAPINFO bmi, *pbmi = &bmi, bmi2, *pbmi2 = &bmi2, bmi3, *pbmi3 = &bmi3, bmi4, *pbmi4 = &bmi4;
JPEG_CORE_PROPERTIES jcprops;
IJLERR jerr;
HMENU hMenu2;
COLORREF RED = 0xFF, BLACK = 0;//xFFFFFF;
CHOOSEFONT cf;

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
WNDPROC pListProc;

LRESULT CALLBACK EditListProc(HWND hwnd2, UINT message, WPARAM wParam, LPARAM lParam)
{
	if ((message == WM_SYSKEYDOWN) && (wParam == 'I'))
		SendMessage(hwndListDlg, WM_COMMAND, IDC_BUTTON1, 0);
	else if ((message == WM_SYSKEYDOWN) && (wParam == 'F'))
		SendMessage(hwndListDlg, WM_COMMAND, IDC_BUTTON1, 0);
	else if ((message == WM_KEYDOWN) && (wParam == VK_RETURN))
		SendMessage(hwndListDlg, WM_COMMAND, (WPARAM)IDOK, 0);
	else if ((message == WM_KEYDOWN) && (wParam == VK_ESCAPE))
		SendMessage(hwndListDlg, WM_COMMAND, (WPARAM)IDCANCEL, 0);
	return CallWindowProc(pListProc, hwnd2, message, wParam, lParam);
}

LRESULT CALLBACK PhotoProc(HWND hwndPhoto, UINT message, WPARAM wParam, LPARAM lParam)
{
//	int xPos, yPos;
	HDC hdcPhoto;
	PAINTSTRUCT psPhoto;

	switch(message)
	{
	case WM_CREATE:
		bmih4.biSize = sizeof(BITMAPINFOHEADER);
		bmih4.biWidth = JpegWidth;
		bmih4.biHeight = -(JpegHeight);// - for right-side-up picture
		bmih4.biPlanes = 1;
		bmih4.biBitCount = 24;
		bmih4.biCompression = BI_RGB;
		bmih4.biSizeImage = 0;
		bmih4.biXPelsPerMeter = 0;
		bmih4.biYPelsPerMeter = 0;
		bmih4.biClrUsed = 0;
		bmih4.biClrImportant = 0;
		bmi4.bmiHeader = *pbmih4;
//		BoxWidth = BoxRight - BoxLeft;
//		BoxHeight = BoxBottom - BoxTop;
//		firstmousemove = TRUE;
		return 0;
/*
	case WM_MOUSEMOVE:
		xPos = LOWORD(lParam);
		yPos = HIWORD(lParam);
		if (firstmousemove)
		{
			firstmousemove = FALSE;
			FirstxPos = xPos;
			FirstyPos = yPos;
			PhotoBoxLeft = FirstxPos - PhotoX;
			PhotoBoxRight = PhotoBoxLeft + BoxWidth;
			PhotoBoxTop = FirstyPos - PhotoY;
			PhotoBoxBottom = PhotoBoxTop + BoxHeight;
		}
		else if ((xPos < PhotoBoxLeft) || (xPos > (PhotoBoxRight)) || (yPos < (PhotoBoxTop)) || (yPos > (PhotoBoxBottom)))
			DestroyWindow(hwndPhoto);
		return 0;
*/
	case WM_PAINT:
		hdcPhoto = BeginPaint(hwndPhoto, &psPhoto);
		SetDIBitsToDevice(hdcPhoto, 0, 0, JpegWidth, JpegHeight, 0, 0, 0, JpegHeight, photo_pixel_buf, pbmi4, DIB_RGB_COLORS);
		EndPaint(hwndPhoto, &psPhoto);
		return 0;

	case WM_KEYDOWN:
		if (wParam == VK_ESCAPE)
			DestroyWindow(hwndPhoto);
//		else if (wParam == 'P')
//		{
//			gotmouseover = FALSE;
//			mouseover = NONE;
//			InvalidateRect(hwnd, &rect, FALSE);
//			DestroyWindow(hwndPhoto);
//		}
		break;

	case WM_DESTROY:
		hwndPhoto = NULL;
		VirtualFree(photo_pixel_buf, 0, MEM_RELEASE);
		photo_pixel_buf = NULL;
		return 0;		
	}
	return DefWindowProc(hwndPhoto, message, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
	MSG          msg;
	WNDCLASS     wndclass;

	hInst = hInstance;
	wndclass.style         = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
	wndclass.lpfnWndProc   = WndProc;
	wndclass.cbClsExtra    = 0;
	wndclass.cbWndExtra    = 0;
	wndclass.hInstance     = hInstance;
	wndclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor       = NULL;//LoadCursor(hInst, MAKEINTRESOURCE(IDC_HAND));//LoadCursor(NULL, IDC_ARROW);//IDC_CURSOR2
	wndclass.hbrBackground = NULL;//(HBRUSH)CreateSolidBrush(LIGHTGRAY);
	wndclass.lpszMenuName  = TEXT("SIMPLEFAMILYTREE");
	wndclass.lpszClassName = szAppName;

	if (!RegisterClass(&wndclass))
		return 0;

	wndclass.lpfnWndProc = PhotoProc;
	wndclass.hIcon = NULL;
	wndclass.lpszClassName = Photos;
	RegisterClass(&wndclass);

	if (szCmdLine[0]!= 0)
	{
		y = 0;
		CmdLine = '\x0';
		if (szCmdLine[0] == '"')
		{
			CmdLine = '"';
			y = 1;
		}
		for (x = 0; szCmdLine[y] != CmdLine ; x++, y++)
			FullFilename[x] = szCmdLine[y];
		FullFilename[x] = 0;
		for ( ; (x > 0) && (FullFilename[x] != '\\'); x--)
			;
		for (x++, y = 0; FullFilename[x] != 0; x++, y++)
			Filename[y] = FullFilename[x];
		Filename[y] = 0;
		fromcommandline = TRUE;
	}

	hwnd = CreateWindow(szAppName, szAppName,
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, NULL, hInstance, NULL);

	ShowWindow(hwnd, SW_SHOWMAXIMIZED);
	UpdateWindow(hwnd);

	while (GetMessage(&msg, NULL, 0, 0))
	{
		if ((hwndIndiv == NULL) || (!IsDialogMessage (hwndIndiv, &msg)) && ((hwndListDlg == NULL) || (!IsDialogMessage (hwndListDlg, &msg))))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	return (int)(WPARAM)msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch(message)
	{
	case WM_SIZE:
		rect.right = LOWORD(lParam);
		rect.bottom = HIWORD(lParam);
		if (Height > rect.bottom)
			Top = Height - rect.bottom;
		else
			Top = 0;
		if (Width > rect.right)
			Left = Width - rect.right;
		else
			Left = 0;
		break;

	case WM_CREATE:
		PhotoDirectory[0] = 0;
		for (x = 0; x < 512; x++)
			Backspace[x] = -1;
		bs = 0;
		RowsUp = MIDROW;
		LastIndiv = 0;//flag
		hBrush = CreateSolidBrush(LIGHTGRAY);
		hHighlightedBrush = CreateSolidBrush(0xC0C0C0);
		hYellowBrush = CreateSolidBrush(0xFFFF);
		first = TRUE;
		Indiv = NULL;
		Buf = NULL;
		GetCurrentDirectory(MAX_PATH, CurrentDir);
		if (FALSE == fromcommandline)
		{
			Filename[0] = 0;
			FullFilename[0] = 0;
		}
		ofn.lStructSize       = sizeof(OPENFILENAME);
		ofn.lpstrFilter       = TEXT(" *.ged\0*.ged\0\0");
		ofn.lpstrCustomFilter = NULL;
		ofn.lpstrFile         = FullFilename;
		ofn.lpstrFileTitle    = Filename;
		ofn.Flags             = OFN_HIDEREADONLY|OFN_NOCHANGEDIR|OFN_OVERWRITEPROMPT;
		ofn.lpstrDefExt       = TEXT("ged");
		ofn.hwndOwner         = hwnd;
		ofn.hInstance         = NULL;
		ofn.nMaxFile          = MAX_PATH;
		ofn.nMaxCustFilter    = 0;
		ofn.nFilterIndex      = 0;
		ofn.nMaxFileTitle     = MAX_PATH;
		ofn.lpstrInitialDir   = CurrentDir;
		ofn.nFileOffset       = 0;
		ofn.nFileExtension    = 0;
		ofn.lCustData         = 0;
		ofn.lpfnHook          = NULL;
		ofn.lpTemplateName    = NULL;

		lf.lfHeight = -11;
		lf.lfWeight = 400;
		lf.lfItalic = 0;
		lf.lfUnderline = 0;
		lf.lfStrikeOut = 0;
		lf.lfCharSet = 0;
		lf.lfOutPrecision = 3;
		lf.lfClipPrecision = 2;
		lf.lfQuality = 1;
		lf.lfPitchAndFamily = 0x22;
		for (x = 0; Arial[x] != 0; x++)
			lf.lfFaceName[x] = Arial[x];
		lf.lfFaceName[x] = 0;
		hFont = CreateFontIndirect(&lf);

		lf2.lfHeight = -15;
		lf2.lfWeight = 400;
		lf2.lfItalic = 0;
		lf2.lfUnderline = 0;
		lf2.lfStrikeOut = 0;
		lf2.lfCharSet = 0;
		lf2.lfOutPrecision = 1;
		lf2.lfClipPrecision = 2;
		lf2.lfQuality = 1;
		lf2.lfPitchAndFamily = 0x31;
		for (x = 0; CourierNew[x] != 0; x++)
			lf2.lfFaceName[x] = CourierNew[x];
		lf2.lfFaceName[x] = 0;
		hFont2 = CreateFontIndirect(&lf2);

		cf.lStructSize    = sizeof (CHOOSEFONT) ;
		cf.hwndOwner      = hwnd ;
		cf.hDC            = NULL ;
		cf.lpLogFont      = &lf ;
		cf.iPointSize     = 0 ;
		cf.Flags          = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS | CF_EFFECTS ;
		cf.rgbColors      = 0 ;
		cf.lCustData      = 0 ;
		cf.lpfnHook       = NULL ;
		cf.lpTemplateName = NULL ;
		cf.hInstance      = NULL ;
		cf.lpszStyle      = NULL ;
		cf.nFontType      = 0 ;      
		cf.nSizeMin       = 0 ;
		cf.nSizeMax       = 0 ;

		cxScreen = GetSystemMetrics(SM_CXFULLSCREEN);
		cyScreen = GetSystemMetrics(SM_CYFULLSCREEN);
		Width = cxScreen;
		Height = cyScreen;
		IndivTop = GetSystemMetrics(SM_CYFRAME);
		IndivTop += GetSystemMetrics(SM_CYCAPTION);
		Frame = GetSystemMetrics(SM_CXSIZEFRAME);
		TitleAndMenu = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYMENU);
		hCursor = LoadCursor(NULL, IDC_HAND);
		hDrawingCursor1 = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR1));
		hDrawingCursor2 = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR2));
		hWaitingCursor = LoadCursor(NULL, IDC_WAIT);
		hArrowCursor = LoadCursor(NULL, IDC_ARROW);
		SetCursor(hArrowCursor);

		hdc = GetDC(hwnd);
		hdcMem = CreateCompatibleDC(hdc);
		hBitmap = CreateCompatibleBitmap(hdc, cxScreen, cyScreen);
		SelectObject(hdcMem, hBitmap);
		SelectObject(hdcMem, hFont);
		SelectObject(hdc, hFont);
		ReleaseDC(hwnd, hdc);
		rectMem.bottom = cyScreen; rectMem.left = 0; rectMem.right = cxScreen; rectMem.top = 0;
		FillRect(hdcMem, &rectMem, hBrush);
		GetTextExtentPoint32(hdcMem, TEXT("j"), 1, &Size);//get Size.cy
		Z = Size.cy*2;
		YSpacing = Z + 10 + (12*2);//12 comes from 17-5, below
		rectMem.bottom = cyScreen; rectMem.left = 0; rectMem.right = cxScreen; rectMem.top = 0;
		SetBkMode(hdcMem, TRANSPARENT);

		if (fromcommandline)
		{
			for (x = 0; x < 512; x++)
				Backspace[x] = -1;
			bs = 0;
			xLoc = yLoc = 0;
			arrayfilled = FALSE;
			fromnewlink = FALSE;
			highlighted = 0xFFFFFFFF;
			IndivNum = 0xFFFFFFFF;
			IndivNumber = 0xFFFFFFFF;
			LastIndiv = 0;
			if (Buf != NULL)
			{
				free(Buf);
				Buf = NULL;
			}
			Fill_Indiv();
			_snwprintf(TitleBar, 300, TEXT(" %s  [%s]"), szAppName, FullFilename);
			SetWindowText(hwnd, TitleBar);
			SendMessage(hwnd, WM_COMMAND, ID_SHOWLISTOFINDIVIDUALS, 0);//show LIST OF INDIVIDUALS
			return 0;
		}

		//x = GetFontLanguageInfo(hdc);
		hFile = CreateFile(FamilyTreeIni, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
		if (hFile != INVALID_HANDLE_VALUE)
		{
			if (fileSize = GetFileSize(hFile, NULL))
			{
				if (fileSize < sizeof(IniBuf))
				{
					utf = (BYTE*)calloc(1, fileSize);
					ReadFile(hFile, utf, fileSize, &dwBytesRead, NULL);
					for (x = 0, y = 0; x < fileSize; )
					{
						if(((utf[x] & MASK3BYTES) == MASK3BYTES) && ((utf[x+1] & MASKBYTE) == MASKBYTE) && ((utf[x+2] & MASKBYTE) == MASKBYTE))
						{// 1110xxxx 10xxxxxx 10xxxxxx
							IniBuf[y++] = ((utf[x] & 0x0F) << 12) | ((utf[x+1] & MASKBITS) << 6) | (utf[x+2] & MASKBITS);
							x += 3;
						}
						else if(((utf[x] & MASK2BYTES) == MASK2BYTES) && ((utf[x+1] & MASKBYTE) == MASKBYTE))
						{// 110xxxxx 10xxxxxx
							IniBuf[y++] = ((utf[x] & 0x1F) << 6) | (utf[x+1] & MASKBITS);
							x += 2;
						}
						else if(utf[x] < MASKBYTE)// 0xxxxxxx
							IniBuf[y++] = (TCHAR)utf[x++];
						else
							IniBuf[y++] = (TCHAR)utf[x++];//not utf-8 character
					}
					free(utf);
					for (x = 0; (IniBuf[x] != '\r') && (x < fileSize); x++)
						FullFilename[x] = IniBuf[x];
					FullFilename[x] = 0;
					GetFileTitle(FullFilename, Filename, MAX_PATH);
					x += 2;//to beginning of second line
					if (x < fileSize)
					{
						if (IniBuf[x] == '@')
						{
							x++;
							if ((IniBuf[x] < '0') || (IniBuf[x] > '9'))//not a number
								x++;
							for (IndivNumber = 0; ((IniBuf[x] >= '0') && (IniBuf[x] <= '9') && (x < fileSize)); x++)//@I71@
								IndivNumber = (IndivNumber * 10) + (IniBuf[x] - '0');
							for ( ; (x < fileSize) && (IniBuf[x] != '\n'); x++)
								;
							if (IniBuf[x] == '\n')
							{
								for ( ; (x < fileSize) && (IniBuf[x] != '='); x++)
									;
								if (IniBuf[x] == '=')
								{
									if ((IniBuf[x+1] == '1') || (IniBuf[x+1] == 'T') || (IniBuf[x+1] == 'Y'))
										showindividual = TRUE;
									else
										showindividual = FALSE;
//									for ( ; (x < fileSize-5) && (IniBuf[x] != '\n'); x++)
//										;
//									if (IniBuf[x] == '\n')
//									{
//										x=x;
//									}
								}
							}
							first = FALSE;
						}
					}
/*
					hKeyFile = CreateFile(KeyFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
					if (hKeyFile != INVALID_HANDLE_VALUE)
					{
						ReadFile(hKeyFile, Key, 6, &dwBytesRead, NULL);
						CloseHandle (hKeyFile);
					}
					TheKey[0] = '4';
					TheKey[1] = '3';
					TheKey[2] = 'y';
					TheKey[3] = 'u';
					TheKey[4] = '2';
					TheKey[5] = '1';
*/
				}
			}
			CloseHandle(hFile);
			DeleteFile(FamilyTreeIni);

			if (first == FALSE)
			{
				Fill_Indiv();
				_snwprintf(TitleBar, 300, TEXT(" %s  [%s]"), szAppName, FullFilename);
				SetWindowText(hwnd, TitleBar);
			}
		}
		return 0;

	case WM_COMMAND:
		wParameter = LOWORD(wParam);
		switch (wParameter)
		{
//		case IDNEW:
//			ofn.lpstrFilter = TEXT(" *.ged\0*.ged\0\0");
//			ofn.lpstrFile = FullFilename;
//			ofn.lpstrFileTitle = Filename;
//			ofn.lpstrTitle = TEXT("Create a Family Tree File");
//			ofn.lpstrDefExt = TEXT("ged");
//			ch = FullFilename[0];
//			FullFilename[0] = 0;
//			goto openfile;

		case OPEN:
/*
			TheKey[0] = '4';
			TheKey[1] = '3';
			TheKey[2] = 'y';
			TheKey[3] = 'u';
			TheKey[4] = '2';
			TheKey[5] = '1';
*/
			PhotoDirectory[0] = 0;
			ch = FullFilename[0];
			ofn.lpstrFilter = TEXT(" *.ged\0*.ged\0\0");
			ofn.lpstrFile = FullFilename;
			ofn.lpstrFileTitle = Filename;
			ofn.lpstrTitle = TEXT("Open a Family Tree File");
			ofn.lpstrDefExt = TEXT("ged");
//openfile:;
			if (GetOpenFileName(&ofn))
			{
				for (x = 0; x < 512; x++)
					Backspace[x] = -1;
				bs = 0;
				xLoc = yLoc = 0;
				arrayfilled = FALSE;
				fromnewlink = FALSE;
				highlighted = 0xFFFFFFFF;
				IndivNum = 0xFFFFFFFF;
				IndivNumber = 0xFFFFFFFF;
				LastIndiv = 0;
				if (Buf != NULL)
				{
					free(Buf);
					Buf = NULL;
				}
				firstphoto = TRUE;
				Fill_Indiv();
				_snwprintf(TitleBar, 300, TEXT(" %s  [%s]"), szAppName, FullFilename);
				SetWindowText(hwnd, TitleBar);
				SendMessage(hwnd, WM_COMMAND, ID_SHOWLISTOFINDIVIDUALS, 0);//show LIST OF INDIVIDUALS
			}
			else
				FullFilename[0] = ch;
			break;

		case PRINT:
			GetClientRect(hwnd, &rect);
			hdc = GetDC(hwnd);
			BitBlt(hdcMem, 0, 0, rect.right, rect.bottom, hdc, 0, 0, SRCCOPY);
			ReleaseDC(hwnd, hdc);
			EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &dwSizeNeeded, &dwNumItems);//get printer name for OpenPrinter
			lpInfo = (LPPRINTER_INFO_5)malloc(dwSizeNeeded);
			EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)lpInfo, dwSizeNeeded, &dwSizeNeeded, &dwNumItems);
			PrinterName[0] = 0;
			if (GetDefaultPrinter(PrinterName, &PrinterNameLen))
			{//show possible default printer first
				if (PrinterName[0] != 0)
				{
					if (IDYES == MessageBox(hwnd, PrinterName, TEXT("Use this printer?"), MB_YESNO))
						goto skip;	
				}
			}
			for ( dwItem = 0; dwItem < dwNumItems; dwItem++ )
			{
				if (wcscmp(lpInfo[dwItem].pPrinterName, PrinterName))
				{
					if (IDYES == MessageBox(hwnd, lpInfo[dwItem].pPrinterName, TEXT("Use this printer?"), MB_YESNO))
					{
						wcscpy(PrinterName, lpInfo[dwItem].pPrinterName);
						break;	
					}
				}
			}
skip:		free(lpInfo);
			if (dwItem == dwNumItems)
				break;//nothing chosen;
			OpenPrinter(PrinterName, &hPrinter, NULL);//get hPrinter for DocumentProperties
			dwNeeded = DocumentProperties(hwnd, hPrinter, PrinterName, NULL, NULL, 0);//get DEVMODE size
			pDevMode = (LPDEVMODE)malloc(dwNeeded);
			DocumentProperties(hwnd, hPrinter, PrinterName, pDevMode, NULL, DM_OUT_BUFFER);//get DEVMODE info
			pDevMode->dmOrientation = DMORIENT_LANDSCAPE;
			DocumentProperties(hwnd, hPrinter, PrinterName, pDevMode, pDevMode, DM_IN_BUFFER|DM_OUT_BUFFER);//integrate landscape selection
			ClosePrinter(hPrinter);
			hDC = CreateDC(TEXT("WINSPOOL"), PrinterName, NULL, pDevMode);
			InvalidateRect(hwnd, &rect, FALSE);
			UpdateWindow(hwnd);
			hdcPrn = CreateCompatibleDC(hDC);
			hPrnBitmap = CreateCompatibleBitmap(hDC, rect.right, rect.bottom);
			hObject = SelectObject(hdcPrn, hPrnBitmap);
			BitBlt(hdcPrn, 0, 0, rect.right, rect.bottom, hdcMem, 0, 0, SRCCOPY);
			w = GetDeviceCaps(hDC, PHYSICALWIDTH);//PHYSICALWIDTH = dpi * 11.0 in Landscape Mode
			z = GetDeviceCaps(hDC, PHYSICALHEIGHT);//PHYSICALHEIGHT = dpi * 8.5 in Landscape Mode
//			if (w > z)
			{//10500 = 10.5" * 1000 & 85 = 8.5 * 10 & 110 = 11.0 * 10 & "/25)*25" rounds down to nearest 25
				x = (((((z * 10500)/85) / rect.right) / 25) * 25);
				y = (((((w * 10500)/110) / rect.right) / 25) * 25);
				if (StartDoc(hDC, &di) > 0)
				{
					if (StartPage(hDC) > 0)
					{//the /100 is there because of the previous w/(8.5*10) and the 10.5*1000
						StretchBlt(hDC, 0, 0, (rect.right * x)/100, (rect.bottom * y)/100, hdcPrn, 0, 0, rect.right, rect.bottom, SRCCOPY);
						if (EndPage(hDC) > 0)
							EndDoc(hDC);
					}
				}
			}
			SelectObject(hdcPrn, hObject);
			DeleteDC(hdcPrn);
			DeleteDC(hDC);
			DeleteObject(hPrnBitmap);
			free(pDevMode);
			break;

		case ID_FILE_EXIT:
			DestroyWindow(hwnd);
			break;

		case ID_FONT:
			if (ChooseFont(&cf))
			{
				hFont = CreateFontIndirect(&lf);
				GetDC(hwnd);
				SelectObject(hdc, hFont);
				SelectObject(hdcMem, hFont);
				ReleaseDC(hwnd, hdc);
				Fill_Indiv();
			}
			break;

		case ID_UNDO:
			UndoIt();
			break;

		case ID_SHOWLISTOFINDIVIDUALS:
			if (LastIndiv)
			{
				if (unlinked)
				{
					unlinked = FALSE;
					if (DestroyWindow(hwndIndiv))
						hwndIndiv = NULL;
				}
				if (hwndListDlg)
				{
					if (DestroyWindow(hwndListDlg))
						hwndListDlg = NULL;
				}
				hwndListDlg = CreateDialog(hInst, TEXT("LIST"), hwnd, ListProc);
			}
			break;

		case ID_NEWINDIVIDUAL:
			DialogBox(hInst, TEXT("NEWINDIVIDUAL"), hwnd, NewIndivProc);
			break;

		case ID_INDIVIDUALSINFO:
			if (highlighted != 0xFFFFFFFF)
			{
				IndivNum = highlighted;
				preditit = TRUE;
				if (hwndIndiv)
				{
					if (DestroyWindow(hwndIndiv))
						hwndIndiv = NULL;
				}
				hwndIndiv = CreateDialog(hInst, TEXT("INDIVIDUAL"), hwnd, IndivProc);
				indivbox = FALSE;
			}
			break;

		case HELP:
			MessageBoxA(hwnd, Help, AppName, MB_OK);
			MessageBoxA(hwnd, Help2, AppName, MB_OK);
			break;
		}
		return 0;

	case WM_MOUSEMOVE:
		if (wParam != MK_LBUTTON)
		{
			xPos = LOWORD(lParam);
			yPos = HIWORD(lParam);
			CursorMoved(xPos, yPos);
		}
		else//if left button down
		{
			SetCursor(hDrawingCursor1);
			if (xPrevious != -1)
			{//normal
				xPrevious = xPos;
				yPrevious = yPos;
			}
			xPos = LOWORD(lParam);
			yPos = HIWORD(lParam);
			if (xPrevious == -1)
			{//initialize it
				xPrevious = xPos;
				yPrevious = yPos;
			}
			xLoc += (xPrevious-xPos);
			yLoc += (yPrevious-yPos);
			if (xLoc < 0)
				xLoc = 0;
			if (xLoc > Left)
				xLoc = Left;
			if (yLoc < 0)
				yLoc = 0;
			if (yLoc > Top)
				yLoc = Top;
			FillhdcMem();
		}
		break;

	case WM_LBUTTONDOWN:
		if (hwndPhoto)
		{
			DestroyWindow(hwndPhoto);
			hwndPhoto = NULL;
		}
//		if (mouseover == PHOTO)
//		{
//			gotmouseover = FALSE;
//			mouseover = NONE;
//			InvalidateRect(hwnd, &rect, FALSE);
//		}

		if (inbox == FALSE)
			SetCursor(hDrawingCursor1);
		else//if (MouseLoc == highlighted)
		{
			if (list)
			{
				list = FALSE;
				if (DestroyWindow(hwndListDlg))
					hwndListDlg = NULL;
			}
			oldHighlighted = highlighted;
			if (MouseLoc < RealLastIndiv)
				highlighted = MouseLoc;
			else
			{
				y = Indiv[MouseLoc].Num;
				for (x = 0; (x < RealLastIndiv) && (Indiv[x].Num != y); x++)
					;
				highlighted = x;
				MouseLoc = x;
			}

			if (bs == 511)
				bs = 0;
			bs++;
			if (Backspace[bs] != -1)
				for (x = 511; x >= bs; x--)
					Backspace[x] = Backspace[x-1];
			Backspace[bs] = highlighted;
			InitializeAgain();
			SendMessage(hwnd, WM_MOUSEMOVE, 0, lParam);
		}
		if (gotmouseover)
		{
			gotmouseover = FALSE;
			if (hwndBirthday)
			{
				DestroyWindow(hwndBirthday);
				hwndBirthday = NULL;
			}
			if (hwndAge)
			{
				DestroyWindow(hwndAge);
				hwndAge = NULL;
			}
		}
		return 0;

	case WM_LBUTTONUP:
		if (inbox == FALSE)
			SetCursor(hDrawingCursor2);
		else
			SetCursor(hCursor);
		return 0;

	case WM_RBUTTONDOWN:
		if (inbox)
		{
			preditit = TRUE;
			IndivNum = MouseLoc;
			if (hwndIndiv)
			{
				if (DestroyWindow(hwndIndiv))
					hwndIndiv = NULL;
			}
			hwndIndiv = CreateDialog(hInst, TEXT("INDIVIDUAL"), hwnd, IndivProc);
			indivbox = FALSE;
		}
		if (gotmouseover)
		{
			gotmouseover = FALSE;
			if (hwndBirthday)
			{
				DestroyWindow(hwndBirthday);
				hwndBirthday = NULL;
			}
			if (hwndAge)
			{
				DestroyWindow(hwndAge);
				hwndAge = NULL;
			}
			if (hwndPhoto)
			{
				DestroyWindow(hwndPhoto);
				hwndPhoto = NULL;
			}
		}
		return 0;

	case 0x020A://WM_MOUSEWHEEL
		if (gotmouseover)
		{
			gotmouseover = FALSE;
			if (hwndBirthday)
			{
				DestroyWindow(hwndBirthday);
				hwndBirthday = NULL;
			}
			if (hwndAge)
			{
				DestroyWindow(hwndAge);
				hwndAge = NULL;
			}
//			if (hwndPhoto)
//			{
//				DestroyWindow(hwndPhoto);
//				hwndPhoto = NULL;
//			}
		}
		if (LOWORD(wParam) == MK_CONTROL)
		{
			if (wParam & 0x80000000)
			{
				if (xLoc < (Left-50))
					xLoc += 50;
				else
					xLoc = Left;
			}
			else if (xLoc > 50)
			{
				xLoc -= 50;
			}
			else
				xLoc = 0;
		}
		else
		{
			if (wParam & 0x80000000)
			{
				if (yLoc < (Top-50))
					yLoc += 50;
				else
					yLoc = Top;
			}
			else if (yLoc > 50)
			{
				yLoc -= 50;
			}
			else
				yLoc = 0;
		}
		CursorMoved(xPos, yPos);
		FillhdcMem();
		return 0;

	case WM_KEYUP:
		Number = 10;
		break;

	case WM_KEYDOWN:
		if (gotmouseover)
		{
			gotmouseover = FALSE;
			if (hwndBirthday)
			{
				DestroyWindow(hwndBirthday);
				hwndBirthday = NULL;
			}
			if (hwndAge)
			{
				DestroyWindow(hwndAge);
				hwndAge = NULL;
			}
//			if (hwndPhoto)
//			{
//				DestroyWindow(hwndPhoto);
//				hwndPhoto = NULL;
//			}
		}
		switch (wParam)
		{
		case 'Z':
			if (GetKeyState(VK_CONTROL) < 0)
				UndoIt();
			break;
		case 'A':
			gotmouseover = FALSE;
			if (hwndAge)
			{
				DestroyWindow(hwndAge);
				hwndAge = NULL;
			}
			if (mouseover == AGE)
			{
				mouseover = NONE;
				InvalidateRect(hwnd, &rect, FALSE);
			}
			else
			{
				mouseover = AGE;
				hdc = GetDC(hwnd);
				SetTextColor(hdc, RED);
				TextOut(hdc, 0, 0, TEXT(" A "), 3);
//				SetTextColor(hdc, BLACK);
				ReleaseDC(hwnd, hdc);
				lParam = xPos;
				lParam |= (yPos << 16);
				SendMessage(hwnd, WM_MOUSEMOVE, 0, lParam);
			}
			break;
		case 'B':
			gotmouseover = FALSE;
			if (hwndBirthday)
			{
				DestroyWindow(hwndBirthday);
				hwndBirthday = NULL;
			}
			if (mouseover == BIRTHDAY)
			{
				mouseover = NONE;
				InvalidateRect(hwnd, &rect, FALSE);
			}
			else
			{
				mouseover = BIRTHDAY;
				hdc = GetDC(hwnd);
				SetTextColor(hdc, RED);
				TextOut(hdc, 0, 0, TEXT(" B "), 3);
//				SetTextColor(hdc, BLACK);
				ReleaseDC(hwnd, hdc);
				lParam = xPos;
				lParam |= (yPos << 16);
				SendMessage(hwnd, WM_MOUSEMOVE, 0, lParam);
			}
			break;
/*
		case 'P':
			gotmouseover = FALSE;
			if (hwndPhoto)
			{
				DestroyWindow(hwndPhoto);
				hwndPhoto = NULL;
			}
			if (mouseover == PHOTO)
			{
				mouseover = NONE;
				InvalidateRect(hwnd, &rect, FALSE);
			}
			else
			{
				mouseover = PHOTO;
				hdc = GetDC(hwnd);
				SetTextColor(hdc, RED);
				TextOut(hdc, 0, 0, TEXT(" P "), 3);
//				SetTextColor(hdc, BLACK);
				ReleaseDC(hwnd, hdc);
				lParam = xPos;
				lParam |= (yPos << 16);
				SendMessage(hwnd, WM_MOUSEMOVE, 0, lParam);
			}
			break;
*/
		case 'P':
			if (photo)
			{
				photo = FALSE;
				FillhdcMem();
			}
			else
			{
				photo = TRUE;
				FillhdcMem();
			}
			InvalidateRect(hwnd, &rect, FALSE);
			break;

		case 'U':
			UndoIt();
			break;
		case 'I':
			SendMessage(hwnd, WM_COMMAND, ID_INDIVIDUALSINFO, 0);
			break;
		case 'L':
//		case VK_RETURN:
			SendMessage(hwnd, WM_COMMAND, ID_SHOWLISTOFINDIVIDUALS, 0);
			break;
		case 'N':
			SendMessage(hwnd, WM_COMMAND, ID_NEWINDIVIDUAL, 0);
			break;
		case 'R':
		case VK_F1:
			SendMessage(hwnd, WM_COMMAND, HELP, 0);
			break;
		case VK_BACK:
			if (bs > 1)
			{
				bs--;
				if (Backspace[511] != -1)
					bs = 511;
				highlighted = Backspace[bs];
				InitializeAgain();
			}
			break;
		case VK_SPACE:
			if ((Backspace[bs+1] != -1) && (bs != 511))
				bs++;
//			else if (bs == 511)
//				bs = 1;
			highlighted = Backspace[bs];
			InitializeAgain();
			break;
		case VK_UP:
			if (yLoc >= Number)
				yLoc -= Number;
			else if (yLoc < Number)
				yLoc = 0;
			CursorMoved(xPos, yPos-Number);
			FillhdcMem();
			Number++;
			break;
		case VK_DOWN:
			if (yLoc < Top)
			{
				if ((yLoc + Number) > Top)
					yLoc = Top;
				else
					yLoc += Number;
				CursorMoved(xPos, yPos+Number);
				FillhdcMem();
				Number++;
			}
			break;
		case VK_RIGHT:
			if ((xLoc + Number) < Left)
				xLoc += Number;
			else
				xLoc = Left;
			CursorMoved(xPos+Number, yPos);
			FillhdcMem();
			Number++;
			break;
		case VK_LEFT:
			if (xLoc > Number)
				xLoc -= Number;
			else
				xLoc = 0;
			CursorMoved(xPos-Number, yPos);
			Number++;
			FillhdcMem();
			break;
		}
		break;

	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);
		if (hdcMem)
		{
			BitBlt(hdc, 0, 0, cxScreen, cyScreen, hdcMem, 0, 0, SRCCOPY);
			if (mouseover == BIRTHDAY)
			{
				SetTextColor(hdc, RED);
				TextOut(hdc, 0, 0, TEXT(" B "), 3);
//				SetTextColor(hdc, BLACK);
			}
			else if (mouseover == AGE)
			{
				SetTextColor(hdc, RED);
				TextOut(hdc, 0, 0, TEXT(" A "), 3);
//				SetTextColor(hdc, BLACK);
			}
//			else if (mouseover == PHOTO)
//			{
//				SetTextColor(hdc, RED);
//				TextOut(hdc, 0, 0, " P ", 3);
//				SetTextColor(hdc, BLACK);
//			}
			if (LastIndiv)
			{
				if (Width > rect.right)
				{
					hWidth = rect.right * rect.right / Width;
					hPos = ((xLoc * rect.right) / Width);
					MoveToEx(hdc, hPos, rect.bottom-5, NULL);
					LineTo(hdc, hPos + hWidth, rect.bottom-5);
					MoveToEx(hdc, hPos, rect.bottom-6, NULL);
					LineTo(hdc, hPos + hWidth, rect.bottom-6);
					MoveToEx(hdc, hPos, rect.bottom-7, NULL);
					LineTo(hdc, hPos + hWidth, rect.bottom-7);
				}
				if (Height > rect.bottom)
				{
					vHeight = rect.bottom * rect.bottom / Height;
					vPos = ((yLoc * rect.bottom) / Height);
					MoveToEx(hdc, rect.right-5, vPos, NULL);
					LineTo(hdc, rect.right-5, vPos + vHeight);
					MoveToEx(hdc, rect.right-6, vPos, NULL);
					LineTo(hdc, rect.right-6, vPos + vHeight);
					MoveToEx(hdc, rect.right-7, vPos, NULL);
					LineTo(hdc, rect.right-7, vPos + vHeight);
				}
			}
		}
		EndPaint(hwnd, &ps);
		break;

	case WM_DESTROY:
		DeleteDC(hdcMem);
		DeleteObject(hBitmap);
		DeleteObject(hBrush);
		DeleteObject(hHighlightedBrush);
		DeleteObject(hYellowBrush);
		if (Buf != NULL)
		{
			for (x = 0; FullFilename[x] != 0; x++)
				IniBuf[x] = FullFilename[x];
			IniBuf[x++] = '\r';
			IniBuf[x++] = '\n';
			IniBuf[x++] = '@';
			IniBuf[x++] = 'I';
			if (highlighted != 0xFFFFFFFF)
			{
				ch = (char)((Indiv[highlighted].Num % 1000000000) / 100000000);
				if (ch)
					IniBuf[x++] = ch + '0';
				ch = (char)((Indiv[highlighted].Num % 100000000) / 10000000);
				if (ch)
					IniBuf[x++] = ch + '0';
				ch = (char)((Indiv[highlighted].Num % 10000000) / 1000000);
				if ((ch) || (IniBuf[x-1] != 'I'))
					IniBuf[x++] = ch + '0';
				ch = (char)((Indiv[highlighted].Num % 1000000) / 100000);
				if ((ch) || (IniBuf[x-1] != 'I'))
					IniBuf[x++] = ch + '0';
				ch = (char)((Indiv[highlighted].Num % 100000) / 10000);
				if ((ch) || (IniBuf[x-1] != 'I'))
					IniBuf[x++] = ch + '0';
				ch = (char)((Indiv[highlighted].Num % 10000) / 1000);
				if ((ch) || (IniBuf[x-1] != 'I'))
					IniBuf[x++] = ch + '0';
				ch = (char)((Indiv[highlighted].Num % 1000) / 100);
				if ((ch) || (IniBuf[x-1] != 'I'))
					IniBuf[x++] = ch + '0';
				ch = (char)((Indiv[highlighted].Num % 100) / 10);
				if ((ch) || (IniBuf[x-1] != 'I'))
					IniBuf[x++] = ch + '0';
				ch = (char)(Indiv[highlighted].Num % 10);
				if ((ch) || (IniBuf[x-1] != 'I'))
					IniBuf[x++] = ch + '0';
				IniBuf[x++] = '@';
				IniBuf[x++] = '\r';
				IniBuf[x++] = '\n';
				for (y = 0; y < 14; x++, y++)
					IniBuf[x] = IniShow[y];
				if (showindividual)
					IniBuf[x++] = 'T';
				else
					IniBuf[x++] = 'F';
				IniBuf[x++] = '\r';
				IniBuf[x++] = '\n';
				utf = (BYTE*)malloc(2*x);
				for (z = 0, y = 0; z < x; z++)
				{
					if (IniBuf[z] < 0x80)
						utf[y++] = (BYTE)IniBuf[z];
					else if (IniBuf[z] < 0x800)
					{
						utf[y++] = ((BYTE)(MASK2BYTES | IniBuf[z] >> 6));
						utf[y++] = ((BYTE)(MASKBYTE | IniBuf[z] & MASKBITS));
					}
					else if(IniBuf[z] < 0x10000)
					{
						utf[y++] = ((BYTE)(MASK3BYTES | IniBuf[z] >> 12));
						utf[y++] = ((BYTE)(MASKBYTE | IniBuf[z] >> 6 & MASKBITS));
						utf[y++] = ((BYTE)(MASKBYTE | IniBuf[z] & MASKBITS));
					}
				}
				hFile = CreateFile(FamilyTreeIni, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
				WriteFile(hFile, utf, y, &dwBytesWritten, NULL);
				FlushFileBuffers(hFile);
				CloseHandle(hFile);
				free(utf);
			}
			free(Buf);
		}
		if (Indiv != NULL)
			free(Indiv);
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd, message, wParam, lParam);
}


//SUBROUTINES////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Fill_Indiv(void)
{
	int gotspouse, Line, ErrorLen;
	int husb, wife, chil[21], num, childnum;
	DWORD birthoffset, birthlocoffset, deathoffset, deathlocoffset, fams;
//	DWORD indivNum;
	BOOL gotname, gotsex, gotnum;

	FillRect(hdcMem, &rectMem, hBrush);
	hdc = GetDC(hwnd);
	FillRect(hdc, &rect, hBrush);
	ReleaseDC(hwnd, hdc);
	if ((fromrestart == FALSE) || (Buf == NULL))
	{
		hFile = CreateFile(FullFilename, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
		if (hFile != INVALID_HANDLE_VALUE)
		{
			if (fileSize = GetFileSize(hFile, NULL))
			{
				utf = (BYTE*)calloc(1, fileSize);
				ReadFile(hFile, utf, fileSize, &dwBytesRead, NULL);
				CloseHandle(hFile);
				Buf = (TCHAR*)calloc(1, (2*fileSize)+10000);//10000 for new individuals
				if ((utf[0] == 0xEF) && (utf[1] == 0xBB) && (utf[2] == 0xBF))
					x = 3;//disregard UTF-8 BOM
				else
					x = 0;
				for (y = 0; x < fileSize; )
				{
					if(((utf[x] & MASK3BYTES) == MASK3BYTES) && ((utf[x+1] & MASKBYTE) == MASKBYTE) && ((utf[x+2] & MASKBYTE) == MASKBYTE))
					{// 1110xxxx 10xxxxxx 10xxxxxx
						Buf[y++] = ((utf[x] & 0x0F) << 12) | ((utf[x+1] & MASKBITS) << 6) | (utf[x+2] & MASKBITS);
						x += 3;
					}
					else if(((utf[x] & MASK2BYTES) == MASK2BYTES) && ((utf[x+1] & MASKBYTE) == MASKBYTE))
					{// 110xxxxx 10xxxxxx
						Buf[y++] = ((utf[x] & 0x1F) << 6) | (utf[x+1] & MASKBITS);
						x += 2;
					}
					else if(utf[x] < MASKBYTE)// 0xxxxxxx
						Buf[y++] = (TCHAR)utf[x++];
					else
						Buf[y++] = (TCHAR)utf[x++];//not utf-8 character
				}
				////////
				fileSize = y;// /= 2;
				////////
				if (FALSE == CheckBuf())
				{
					DestroyWindow(hwnd);
					return;
				}
				free(utf);
			}
			else//if (fileSize == 0)
			{
				CloseHandle(hFile);
//				MessageBox(hwnd, "...is empty.  Deleting it...", FullFilename, MB_OK);
//				DeleteFile(FullFilename);
				return;
			}
		}
		else//new file
			return;
	}
	for (x = 0, LastIndiv = 0; x < fileSize; x++)
	{
		if ((Buf[x] == '0') && (Buf[x+1] == ' ') && (Buf[x+2] == '@') && ((Buf[x-1] == '\n') || (Buf[x-1] == '\r')))
		{
			for (y = x; (Buf[y] != '\r') && (Buf[y] != '\n'); y++)
			{
				if ((Buf[y] == 'I') && (Buf[y+1] == 'N') && (Buf[y+2] == 'D') && (Buf[y+3] == 'I')) 
				{
					LastIndiv++;
					break;
				}
			}
		}
	}
	LastIndiv++;
	if (Indiv != NULL)
	{
		free(Indiv);
		Indiv = NULL;
	}
	Indiv = (struct INDIV*)malloc((LastIndiv + EXTRAIDIVIDUALS) * sizeof(struct INDIV));//+EXTRAIDIVIDUALS for duplicates
	for (x = 0 ; x < (DWORD)(LastIndiv+EXTRAIDIVIDUALS); x++)//+EXTRAIDIVIDUALS for duplicates
	{
		Indiv[x].Num = 0;
		Indiv[x].Childof = 0;
		for (y = 0; y < MAXSPOUSES; y++)
			Indiv[x].Spouseof[y] = 0;
		Indiv[x].Name = 0;
		Indiv[x].Note = 0;
		Indiv[x].Sex = 0;
		Indiv[x].Birth = 0;
		Indiv[x].BirthLoc = 0;
		Indiv[x].Death = 0;
		Indiv[x].DeathLoc = 0;
		Indiv[x].Parent = 0;
		Indiv[x].Spouse = 0;
		Indiv[x].Child = 0;
		Indiv[x].cx = 0;
		Indiv[x].X = 0;
		Indiv[x].LeftChild = 0;
		Indiv[x].RightChild = 0;
		Indiv[x].ArrayX = 0;
		Indiv[x].ArrayY = 0;
		Indiv[x].Flags = 0;
	}
	oi = 0;

	gotnum = FALSE;
	gotname = TRUE;
	gotsex = TRUE;
	i = 0;
	Line = 1;
	for (x = 0; x < fileSize; x++)
	{
x22:	if ((Buf[x] == '\r') || (Buf[x] == '\n'))
		{
			Line++;
			if (Buf[x] == '\r')
				x++;
			if (x < (fileSize-1))
			{
				if (((Buf[x+1] < '0') || (Buf[x+1] > '9'))
				 || (Buf[x+2] != ' ')
				 || ((Buf[x+3] >= '0') && (Buf[x+3] <= '9')))
				{//bad format in gedcom file
					DWORD X, Y;

					if ((Buf[x+1] == '\r') && (Buf[x+2] == '\n'))
					{//a blank line
						x += 2;
						goto x22;
					}
					for (X = Y = x+1; ((X-Y) < 300) && (Buf[X] != '\r') && (Buf[X] != '\n'); X++)
						;
					ch = Buf[X];
					Buf[X] = 0;
					_snwprintf(Error, 512, TEXT("The line  \"%s\"  in\n%s\nis bad (fix it in Notepad\nby making it conform to\nthe format of similar but good lines,\nand tell\njdmcox@jdmcox.com about it).\nBut BEFORE YOU DO THAT, SEE THE NEXT MESSAGE..."), &Buf[Y], FullFilename);
					Buf[X] = ch;
					MessageBox(hwnd, Error, Filename, MB_OK);
					UndoIt();
					return;
				}
			}
			if ((Buf[x+1] == '0') && (Buf[x+2] == ' ') && (Buf[x+3] == '@'))
			{
				x += 4;//to possible individual's number
				for (y = x; (Buf[y] != '\r') && (Buf[y] != '\n'); y++)
					if ((Buf[y] == 'I') && (Buf[y+1] == 'N') && (Buf[y+2] == 'D') && (Buf[y+3] == 'I'))
						break;
				if (Buf[y] == 'I')
				{//INDI
					if (gotname == FALSE)
					{
						_snwprintf(Error, 512, TEXT("Missing /NAME/ after 0 @I%u@ INDI\nin %s\n(which can be edited in Notepad)"), Indiv[i].Num, FullFilename);
						MessageBox(hwnd, Error, Filename, MB_OK);
						DestroyWindow(hwnd);
						return;
					}
//					if (gotsex == FALSE)
//					{
//						_snwprintf(Error, 512, TEXT("Missing SEX after 0 @I%d@ INDI\nin %s\n(which can be edited in Notepad)"), Indiv[i].Num, FullFilename);
//						MessageBox(hwnd, Error, Filename, MB_OK);
//						DestroyWindow(hwnd);
//						return;
//					}
					gotspouse = 0xFFFF;
					Fams = x;
					gotname = FALSE;
					gotsex = FALSE;
					famchild = 0;
					birthoffset = deathoffset = birthlocoffset = deathlocoffset = 0xFFFFFFFF;
					i++;
					if (Buf[x] >= 'A')
						x++;//ignore leading letter
					for (Indiv[i].Num = 0; Buf[x] != '@'; x++)
						Indiv[i].Num = (Indiv[i].Num * 10) + (Buf[x] - '0');
					if ((Indiv[i].Num == IndivNumber) && (fromnewlink == FALSE))
					{
						if ((IndivNum == 0xFFFFFFFF) && (highlighted == 0xFFFFFFFF))
						{
							IndivNum = i;
							highlighted = i;
						}
					}
					gotnum = TRUE;
				}
				else
					gotnum = FALSE;
			}
			else if (gotnum == FALSE)
				continue;
			else if ((Buf[x+1] == '1') && (Buf[x+2] == ' ') && (Buf[x+3] == 'N') && (Buf[x+4] == 'A') && (Buf[x+5] == 'M') && (Buf[x+6] == 'E'))//1 NAME 
			{//NAME
				if (gotname)
					continue;
				x += 8;
				for (y = x; (Buf[y] != '\n') && (y < fileSize); y++) {
					if (Buf[y] == '/') {
						for ( ; (Buf[y] != '\n') && (y < fileSize); y++) {
							if (Buf[y] == '/') {
								gotname = TRUE;
								goto x0;
							}
						}
					}
				}
x0:				Indiv[i].Name = x;
			}
			else if ((Buf[x+1] == '1') && (Buf[x+2] == ' ') && (Buf[x+3] == 'S') && (Buf[x+4] == 'E') && (Buf[x+5] == 'X'))
			{//SEX
				if (Buf[x+7] == 'M')
				{
					Indiv[i].Sex = 1;
					gotsex = TRUE;
				}
				else if (Buf[x+7] == 'F')
				{
					Indiv[i].Sex = 0xFFFF;
					gotsex = TRUE;
				}
			}
			else if ((Buf[x+1] == '1') && (Buf[x+2] == ' ') && (Buf[x+3] == 'B') && (Buf[x+4] == 'I') && (Buf[x+5] == 'R') && (Buf[x+6] == 'T'))
			{//BIRT
				for (x++; Buf[x] != '\n'; x++)
					;
				if ((Buf[x+1] == '2') && (Buf[x+2] == ' ') && (Buf[x+3] == 'D') && (Buf[x+4] == 'A') && (Buf[x+8] != '\r') && (Buf[x+8] != '\n'))//DATE after \r\n
				{//2 BIRT 13 APR 1938
					x += 8;
					if (birthoffset == 0xFFFFFFFF)
					{
						birthoffset = x;
						Indiv[i].Birth = x;
						for ( ; Buf[x] != '\n'; x++)
							;
						if ((Buf[x+1] == '2') && (Buf[x+2] == ' ') && (Buf[x+3] == 'P') && (Buf[x+4] == 'L') && (Buf[x+5] == 'A') && (Buf[x+6] == 'C'))
						{
							x += 8;
							if (birthlocoffset == 0xFFFFFFFF)
								birthlocoffset = x;
							else
								Indiv[i].Flags |= 0x10;
							Indiv[i].BirthLoc = x;
						}
						else
							x--;
					}
					else
					{
						Indiv[i].Flags |= 1;
//						for (y = Indiv[i].Name; (Buf[y] != '\r') && (Buf[y] != '\n'); y++)
//							;
//						ch = Buf[y];
//						Buf[y] = 0;
//						ErrorLen = _snwprintf(Error, "%s has more than one birth date.\r\n", &Buf[Indiv[i].Name]);
//						Buf[y] = ch;
//						WriteFile(hErrorFile, Error, ErrorLen, &dwBytesWritten, NULL);
					}	
				}
				else if ((Buf[x+1] == '2') && (Buf[x+2] == ' ') && (Buf[x+3] == 'P') && (Buf[x+4] == 'L') && (Buf[x+5] == 'A') && (Buf[x+6] == 'C'))//PLAC after \r/n
				{
					x += 8;
					if (birthlocoffset == 0xFFFFFFFF)
					{
						birthlocoffset = x;
						Indiv[i].BirthLoc = x;
					}
					else
					{
						Indiv[i].Flags |= 0x10;
//						for (y = Indiv[i].Name; (Buf[y] != '\r') && (Buf[y] != '\n'); y++)
//							;
//						ch = Buf[y];
//						Buf[y] = 0;
//						ErrorLen = _snwprintf(Error, "%s has more than one birth place.\r\n", &Buf[Indiv[i].Name]);
//						Buf[y] = ch;
//						WriteFile(hErrorFile, Error, ErrorLen, &dwBytesWritten, NULL);
					}	
				}
				else
					x--;
			}
			else if ((Buf[x+1] == '1') && (Buf[x+2] == ' ') && (Buf[x+3] == 'D') && (Buf[x+4] == 'E') && (Buf[x+5] == 'A') && (Buf[x+6] == 'T'))
			{//DEAT
				for (x++; Buf[x] != '\n'; x++)
					;
				if ((Buf[x+1] == '2') && (Buf[x+2] == ' ') && (Buf[x+3] == 'D') && (Buf[x+4] == 'A') && (Buf[x+8] != '\r') && (Buf[x+8] != '\n'))//DATE after \r\n
				{//2 BIRT 13 APR 1938
					x += 8;
					if (deathoffset == 0xFFFFFFFF)
					{
						deathoffset = x;
						Indiv[i].Death = x;
						for ( ; Buf[x] != '\n'; x++)
							;
						if ((Buf[x+1] == '2') && (Buf[x+2] == ' ') && (Buf[x+3] == 'P') && (Buf[x+4] == 'L') && (Buf[x+5] == 'A') && (Buf[x+6] == 'C'))
						{
							x += 8;
							if (deathlocoffset == 0xFFFFFFFF)
								deathlocoffset = x;
							else
								Indiv[i].Flags |= 0x1000;
							Indiv[i].DeathLoc = x;
						}
						else
							x--;
					}
					else
					{
						Indiv[i].Flags |= 0x100;
//						for (y = Indiv[i].Name; (Buf[y] != '\r') && (Buf[y] != '\n'); y++)
//							;
//						ch = Buf[y];
//						Buf[y] = 0;
//						ErrorLen = _snwprintf(Error, "%s has more than one death date.\r\n", &Buf[Indiv[i].Name]);
//						Buf[y] = ch;
//						WriteFile(hErrorFile, Error, ErrorLen, &dwBytesWritten, NULL);
					}	
				}
				else if ((Buf[x+1] == '2') && (Buf[x+2] == ' ') && (Buf[x+3] == 'P') && (Buf[x+4] == 'L') && (Buf[x+5] == 'A') && (Buf[x+6] == 'C'))//PLAC after \r\n
				{
					x += 8;
					if (deathlocoffset == 0xFFFFFFFF)
					{
						deathlocoffset = x;
						Indiv[i].DeathLoc = x;
					}
					else
					{
						Indiv[i].Flags |= 0x1000;
//						for (y = Indiv[i].Name; (Buf[y] != '\r') && (Buf[y] != '\n'); y++)
//							;
//						ch = Buf[y];
//						Buf[y] = 0;
//						ErrorLen = _snwprintf(Error, "%s has more than one death place.\r\n", &Buf[Indiv[i].Name]);
//						Buf[y] = ch;
//						WriteFile(hErrorFile, Error, ErrorLen, &dwBytesWritten, NULL);
					}	
				}
				else
					x--;
			}
			else if ((Buf[x+1] == '1') && (Buf[x+2] == ' ') && (Buf[x+3] == 'F') && (Buf[x+4] == 'A') && (Buf[x+5] == 'M'))
			{
				famcfirst = TRUE;
				if (Buf[x+6] == 'C')//child of
				{//FAMC
					if (famchild < 2)
					{
						if (famchild == 1)
							Indiv[i].Flags |= 0x10000;
						famchild++;
						if (gotspouse == 1)
							famcfirst = FALSE;
						x += 9;//to family number
						if (Buf[x] >= 'A')
							x++;//ignore leading letter
						for (Indiv[i].Childof = 0 ; Buf[x] != '@'; x++)
							Indiv[i].Childof = (Indiv[i].Childof * 10) + (Buf[x] - '0');
					}
					else
					{
						for (y = Indiv[i].Name; (Buf[y] != '\r') && (Buf[y] != '\n'); y++)
							;
						ch = Buf[y];
						Buf[y] = 0;
						MessageBox(hwnd, TEXT("%s is a child of more than two couples!\r\n"), &Buf[Indiv[i].Name], MB_OK);
						Buf[y] = ch;
					}
				}
				else if (Buf[x+6] == 'S')//spouse of
				{//FAMS
					gotspouse = 1;
					x += 9;//to family number
					if (Buf[x] >= 'A')
						x++;//ignore leading letter
					for (y = 0; y < MAXSPOUSES; y++)
					{
						if (Indiv[i].Spouseof[y] == 0)
						{
							for ( ; Buf[x] != '@'; x++)
								Indiv[i].Spouseof[y] = (Indiv[i].Spouseof[y] * 10) + (Buf[x] - '0');
						}
					}
				}
			}
			else if ((Buf[x+1] == '1') && (Buf[x+2] == ' ') && (Buf[x+3] == 'N') && (Buf[x+4] == 'O') && (Buf[x+5] == 'T') && (Buf[x+6] == 'E'))
			{//NOTE
				Indiv[i].Note = x+8;
			}
		}//end of if ((Buf[x] == '\r') || (Buf[x] == '\n'))
	}//end of for (x = 0

	LastIndivNum = Fams;
	for (y = 0; Fams < fileSize; Fams++)
	{//point to 0 @F1@ FAM
		if ((Buf[Fams-1] == '\n') && (Buf[Fams] == '0'))
		{
			if ((Buf[Fams+2] == 'T') && (Buf[Fams+3] == 'R') && (Buf[Fams+4] == 'L') && (Buf[Fams+5] == 'R'))
				break;
			for (x = Fams; (x < fileSize) && (Buf[x] != '\n'); x++)
			{
				if ((Buf[x] == 'F') && (Buf[x+1] == 'A') && (Buf[x+2] == 'M'))
					goto gotfams;
			}
		}
	} 
gotfams:;
	if (gotname == FALSE)
	{
		_snwprintf(Error, 512, TEXT("Missing /NAME/ after 0 @I%u@ INDI line\nin %s\n(which can be edited in Notepad)"), Indiv[i].Num, FullFilename);
		MessageBox(hwnd, Error, Filename, MB_OK);
		DestroyWindow(hwnd);
		return;
	}
//	if (gotsex == FALSE)
//	{
//		_snwprintf(Error, "Missing SEX after 0 @%d@ INDI line\nin %s\n(which can be edited in Notepad)", Indiv[i].Num, FullFilename);
//		MessageBox(hwnd, Error, Filename, MB_OK);
//		DestroyWindow(hwnd);
//		return;
//	}
	for (x = Fams; Buf[x] != '\n'; x++)
	{
		if (Buf[x] == '@')
		{
			x++;
			if ((Buf[x] < '0') || (Buf[x] > '9'))
				x++;
			if ((Buf[x] == '0') && (Buf[x+1] == '@'))
			{
				for ( ; (Buf[x] != '\r') && (Buf[x] != '\n'); x++)
					;
				ch = Buf[x];
				Buf[x] = 0;
				_snwprintf(Error, 512, TEXT("The line\n%s\nis going to cause problems\nif you edit anything."), &Buf[Fams]);
				MessageBox(hwnd, Error, Filename, MB_OK);
				Buf[x] = ch;
			} 
		}
	}
	for (FamsEnd = Fams; FamsEnd < fileSize; FamsEnd++)
	{//get FamsEnd
		if ((Buf[FamsEnd-1] == '\n') && (Buf[FamsEnd] == '0') && (Buf[FamsEnd+2] != '@'))
			break;
	}
	i++;
	LastIndiv = i;
	RealLastIndiv = i;
	fromnewlink = FALSE;

	//check for copies of spouse in Spouseof
	for (x = 1; x < LastIndiv; x++)
	{
		for (s = 0; (s < MAXSPOUSES) && (Indiv[x].Spouseof[s]); s++)
			if (Indiv[x].Spouseof[s] == Indiv[x].Spouseof[s+1])
			{
				for (y = Indiv[x].Name; (Buf[y] != '\r') && (Buf[y] != '\n'); y++)
					;
				ch = Buf[y];
				Buf[y] = 0;
				ErrorLen = _snwprintf(Error, 512, TEXT("has multiple occurrences of the same spouse.\r\nOpen %s\r\nin Notepad and delete the extra ones.\r\n"), Filename);
				MessageBox(hwnd, Error, &Buf[Indiv[x].Name], MB_OK);
				Buf[y] = ch;
				for (s = 3; s; s--)
				{//fix Indiv[x].Spouseof
					if (Indiv[x].Spouseof[s] == Indiv[x].Spouseof[s-1])
						Indiv[x].Spouseof[s] = 0;
				}
				break;
			}
	}

	//check for multiple HUSB & WIFE & CHIL(with same @Inumber@) in FAM records
	for (x = Fams; x < FamsEnd; x++)
	{//0 @F123@ FAM
		if (Buf[x-1] == '\n')
		{
			if ((Buf[x] == '0') && (Buf[x+2] == '@'))// && (Buf[x+3] == 'F')
			{
//
				gotit = FALSE;
				test = x + 3;
				if ((Buf[test] < '0') || (Buf[test] > '9'))
					test++;
				for (test2 = test; Buf[test2] != '\n'; test2++)
				{
					if ((Buf[test2] == 'F') && (Buf[test2+1] == 'A')  && (Buf[test2+2] == 'M')) 
					{
						gotit = TRUE;
						break;
					}
				}
				if (gotit == FALSE)
					continue;
//
				husb = wife = num = 0;
				for (y = 0; y < 21; y++)
					chil[y] = 0;
//				y = x+3;
//				if ((Buf[y] < '0') || (Buf[y] > '9'))
//					y++;
//				fams = Atoi(&Buf[y]);
				fams = Atoi(&Buf[test]);
				for (y = x, z = 0; (Buf[y] != '\r') && (Buf[y] != '\n'); y++, z++)
					temp[z] = Buf[y];
				temp[z] = 0;
			}
			if ((Buf[x] == '1') && (Buf[x+2] == 'H') && (Buf[x+3] == 'U') && (Buf[x+4] == 'S'))
			{
				y = x+8;
				if ((Buf[y] < '0') || (Buf[y] > '9'))
					y++;
				if (husb)
				{
//					indivNum = Atoi(&Buf[y]);
//					for (i = 0; i < LastIndiv; i++)
//					{
//						if (Indiv[i].Num == indivNum)
//						{
//							for (s = 0; (s < MAXSPOUSES) && Indiv[i].Spouseof[s]; s++)
//							{
//								if ((Indiv[i].Spouseof[s] == fams) && (Indiv[i].Sex == 1))
//									x=x;
//							}
//						}
//					}
					ErrorLen = _snwprintf(Error, 512, TEXT("Family record %s has more than one HUSB (husband).\r\n"), temp);
					MessageBox(hwnd, Error, Filename, MB_OK);
				}
				else
//					husb = Atoi(&Buf[y]);
					husb = fams;
			}
			if ((Buf[x] == '1') && (Buf[x+2] == 'W') && (Buf[x+3] == 'I') && (Buf[x+4] == 'F'))
			{
				if (wife)
				{
					ErrorLen = _snwprintf(Error, 512, TEXT("Family record %s has more than one WIFE.\r\n"), temp);
					MessageBox(hwnd, Error, Filename, MB_OK);
				}
				else
					wife++;
			}
			if ((Buf[x] == '1') && (Buf[x+2] == 'C') && (Buf[x+3] == 'H') && (Buf[x+4] == 'I'))
			{
				y = x+8;
				if ((Buf[y] < '0') || (Buf[y] > '9'))
					y++;
				childnum = Atoi(&Buf[y]);
				for (y = 0; chil[y] != 0; y++)
				{
					if (childnum == chil[y])
					{
						ErrorLen = _snwprintf(Error, 512, TEXT("Family record %s has same CHIL (child) repeated.\r\n"), temp);
						MessageBox(hwnd, Error, Filename, MB_OK);
					}
				}
				chil[num++] = childnum; 
			}
		}
	}
	for (i = 0; i < LastIndiv; i++)// to the same folder as the file just opened.
	{//move FAMS for single parent to Spouseof[0] (make it the first spouseof)
		for (s = 1; (s < MAXSPOUSES) && (Indiv[i].Spouseof[s]); s++)
		{
			for (w = 0; w < LastIndiv; w++)
			{
				if (w == i)
					continue;
				for (ws = 0; (ws < MAXSPOUSES) && (Indiv[w].Spouseof[ws]); ws++)
				{
					if ((Indiv[w].Spouseof[ws] & 0x7FFFFFFF) == (Indiv[i].Spouseof[s] & 0x7FFFFFFF))
					{
						goto x4;//single parent not found yet
					}
				}
			}
			v = Indiv[i].Spouseof[s];
			for (w = 1; w <= s; w++)
				Indiv[i].Spouseof[w] = Indiv[i].Spouseof[w-1];
			Indiv[i].Spouseof[0] = v;//done
			goto x4;
		}
x4:;
	}
	if (LastIndiv == 2)
	{//one time only special deal
		highlighted = 1;
		Backspace[1] = 1;
		IndivNum = 1;
	}
	SortSiblings();
//	CheckFAMS();

	if ((highlighted != 0xFFFFFFFF) && (Buf))
		///////////
		FillArray();
		///////////
}


void FillArray(void)
{
	SetCursor(hWaitingCursor);
	CheckForPhotos();
	for (y = 0; y < ROWS; y++)
	{
		for (x = 0; x < COLS; x++)
		{
			Array[y][x] = 0xFFFF;
		}
		indiv[y] = 0;
		Col[y] = 0;
	}
	z = highlighted;
	ArrayUp = (DWORD*)calloc(1, ROWSUP*BIGCOLS*sizeof(DWORD));
	ArrayUp[MIDROW*BIGCOLS] = highlighted;
	Array[MIDROW][0] = highlighted;
	TotalParents = 2;
	for (row = MIDROW - 1, notempty = TRUE; (notempty) && (row > 5); row--, TotalParents *= 2)//row > 3
	{//put ancestors in ArrayUp
		notempty = FALSE;
		for (col = 0, Child = 0, Parents = 0, ptr = 0; Child < (TotalParents/2); Child++, col += 2)
		{//get all parents
			if (ptr > COLS)
			{
				MessageBox(hwnd, TEXT("Too many columns"), ERROR, MB_OK);
				highlighted = oldHighlighted;
				bs--;
				return;
			}	
			z = ArrayUp[((row+1)*BIGCOLS)+Child];
			if (z == 0)
				continue;
			v = Indiv[z].Childof;
			for (i = 1; i < RealLastIndiv; )
			{//get two parents
				for (parent = 0; i < RealLastIndiv; i++)
				{
					for (s = 0; (s < MAXSPOUSES) && (Indiv[i].Spouseof[s] != 0); s++)
					{
						if (v == Indiv[i].Spouseof[s])
						{
							for (y = MIDROW-1; y >= row; y--)
							{
								for (x = 0; Array[y][x] != 0xFFFF; x++)
								{
									if (Array[y][x] == i)
									{//if duplicate individual in Indiv (e.g.married cousins)
										Indiv[LastIndiv] = Indiv[i];
										Indiv[LastIndiv].Child = TRUE;
										Indiv[z].Parent = LastIndiv;
										notempty = TRUE;
										ArrayUp[(row*BIGCOLS)+(col+parent)] = LastIndiv;
										Array[row][ptr++] = LastIndiv;
										if (parent == 1)//second parent
										{
											Indiv[LastIndiv].Spouse = FirstParent;
											Indiv[FirstParent].Spouse = LastIndiv++;
											goto x2;
										}
										FirstParent = LastIndiv++;
										parent++;
										goto x3;//found match
									}
								}
							}
							Indiv[i].Child = TRUE;
							Indiv[z].Parent = i;
							notempty = TRUE;
							ArrayUp[(row*BIGCOLS)+(col+parent)] = i;
							Array[row][ptr++] = i;
							if (parent == 1)//second parent
							{
								Indiv[i].Spouse = FirstParent;
								Indiv[FirstParent].Spouse = i;
								goto x2;
							}
							FirstParent = i;
							parent++;
							goto x3;//found match
						}
					}
x3:;
				}
			}//end of for (i = 1; i < LastIndiv; )
x2:			Parents += 2;
		}
	}
	RowsUp = row + 2;
	free(ArrayUp);

//get ancestors Indiv[I].cx
	for (y = MIDROW; y >= RowsUp; y--)
	{
		X = cxScreen*25;
		for (x = 0; Array[y][x] != 0xFFFF; x++)
		{
			I = Array[y][x];
			w = GetName();
			GetTextExtentPoint32(hdcMem, temp, w, &Size);
			Indiv[I].ArrayX = (WORD)x;
			Indiv[I].ArrayY = (WORD)y;
			Indiv[I].cx = (WORD)Size.cx;
			Indiv[I].X = X;
			X += Size.cx + 24;
		}
	}

//get ancestors Indiv[I].X
	endlessloop = 0;
begin:;
	if (endlessloop >= 100000)
	{
//	for (x = 0, biggest = 0; x < RealLastIndiv; x++)
//	{
//		if (Indiv[x].X > biggest)
//		{
//			biggest = Indiv[x].X;
//			z = x;
//		}
//	}
//	if (Indiv[z].X > 100000)
//	{	
		for (x = Indiv[highlighted].Name; (Buf[x] != '\r') && (Buf[x] != '\n'); x++)
			;
		ch = Buf[x];
		Buf[x] = 0;
		_snwprintf(Error, 512, TEXT("A loop didn't finish executing\nin the ancestor routine when\n%s\nwas selected."), &Buf[Indiv[highlighted].Name]);
		Buf[x] = ch;
		MessageBox(hwnd, Error, ERROR, MB_OK);
		highlighted = oldHighlighted;
		bs--;
		DestroyWindow(hwnd);
		return;
	}
	for (y = MIDROW; y >= RowsUp; y--)
	{
		for (x = 0; Array[y][x] != 0xFFFF; x++)
		{
			Child = Array[y][x];
			Parent = Indiv[Child].Parent;
			if (Parent)
			{
				LinefromChildX = Indiv[Child].X + (Indiv[Child].cx/2);
				ParentSpouse = Indiv[Parent].Spouse;
				if (ParentSpouse)
				{
					if (Indiv[ParentSpouse].Parent == FALSE)
						Indiv[ParentSpouse].X = Indiv[Parent].X - 24 - Indiv[ParentSpouse].cx;//special case
					SpouseLineLen = Indiv[Parent].X - (Indiv[ParentSpouse].X + Indiv[ParentSpouse].cx);
					LinetoChildX = Indiv[ParentSpouse].X + Indiv[ParentSpouse].cx + (SpouseLineLen/2);
					if (LinetoChildX != LinefromChildX)
					{
						oldX = Indiv[ParentSpouse].X;
						if (Indiv[ParentSpouse].ArrayX == 0)
						{//move to left
							Indiv[ParentSpouse].X = LinefromChildX - (SpouseLineLen/2) - Indiv[ParentSpouse].cx;
							newX = Indiv[ParentSpouse].X;
							Indiv[Parent].X += newX - oldX;
						}
						else
						{//move to right 
							if (Indiv[Parent].X < (LinefromChildX + (SpouseLineLen/2)))
							{
								Indiv[ParentSpouse].X = LinefromChildX - (SpouseLineLen/2) - Indiv[ParentSpouse].cx;
								newX = Indiv[ParentSpouse].X;
								Indiv[Parent].X += newX - oldX;
							}
							else
							{//move child to right
								oldX = Indiv[Child].X;
								Indiv[Child].X = LinetoChildX - (Indiv[Child].cx/2);
								newX = Indiv[Child].X;
								ArrayX = Indiv[Child].ArrayX;
								ArrayY = Indiv[Child].ArrayY;
								for (z = ArrayX+1; Array[y][z] != 0xFFFF; z++)
									Indiv[Array[y][z]].X += newX - oldX;
								endlessloop++;
								goto begin;
							}
						}
						ArrayX = Indiv[Parent].ArrayX;
						ArrayY = Indiv[Parent].ArrayY;
						for (z = ArrayX+1; Array[y-1][z] != 0xFFFF; z++)
							Indiv[Array[y-1][z]].X += newX - oldX;
					}
				}
				else//no ParentSpouse
				{
					LinetoChildX = Indiv[Parent].X + (Indiv[Parent].cx/2);
					if (LinetoChildX != LinefromChildX)
					{
						oldX = Indiv[Parent].X;
						if (Indiv[Parent].ArrayX == 0)
						{//move to left
							Indiv[Parent].X = LinefromChildX - (Indiv[Parent].cx/2);
							newX = Indiv[Parent].X;
						}
						else
						{//move to right 
							if (Indiv[Parent].X < (LinefromChildX - (Indiv[Parent].cx/2)))
							{
								Indiv[Parent].X = LinefromChildX - (Indiv[Parent].cx/2);
								newX = Indiv[Parent].X;
							}
							else
							{//move child to right
								oldX = Indiv[Child].X;
								Indiv[Child].X = LinetoChildX - (Indiv[Child].cx/2);
								newX = Indiv[Child].X;
								ArrayX = Indiv[Child].ArrayX;
								ArrayY = Indiv[Child].ArrayY;
								for (z = ArrayX+1; Array[y][z] != 0xFFFF; z++)
									Indiv[Array[y][z]].X += newX - oldX;
								endlessloop++;
								goto begin;
							}
						}
						ArrayX = Indiv[Parent].ArrayX;
						ArrayY = Indiv[Parent].ArrayY;
						for (z = ArrayX+1; Array[y-1][z] != 0xFFFF; z++)
							Indiv[Array[y-1][z]].X += newX - oldX;
					}
				}
			}
		}
	}

//MessageBox(hwnd, _itoa(endlessloop, asdf, 10), "", MB_OK);

	AncestorMinX = 0xFFFFFFFF;
	for (y = RowsUp; (y < ROWS) && (Array[y][0] != 0xFFFF) && (y < (MIDROW+1)); y++)
		if (Indiv[Array[y][0]].X < AncestorMinX)
			AncestorMinX = Indiv[Array[y][0]].X;
	AncestorMinX -= 50;
	for (y = RowsUp; y < (MIDROW+1); y++)
		for (x = 0; Array[y][x] != 0xFFFF; x++)
		{
			Indiv[Array[y][x]].X -=	AncestorMinX;
			Indiv[Array[y][x]].Flags |= 0x1000000;
		}
	HighlightedAncestorX = Indiv[highlighted].X + (Indiv[highlighted].cx/2);


//get descendants Array[y][x]
	firstime = TRUE;
	inbox = FALSE;
	row = MIDROW;
	w = highlighted;
	Array[row][Col[row]++] = highlighted;
	if (Indiv[highlighted].Spouseof[0])
	{//fill Array
		while (TRUE)
		{
			indiv[row] = highlighted;
			if ((GetSpouse() == FALSE) && (firstime == FALSE))//tricky
				break;//exit routine
			firstime = FALSE;
			do
			{
				if (GetChild())
				{//look for spouse of child
					if (FALSE == GetSpouse())//if no spouse of child
						row--;//back to where it was
				}
				else if (w == LastIndiv)//no child
					row--;//back to where it was
				if (nogood)
				{
					highlighted = oldHighlighted;
					bs--;
					DestroyWindow(hwnd);
					return;
				}
			} while (row >= MIDROW);
			row = MIDROW;
		}
	}

//get descendants Indiv[I].cx
	for (y = MIDROW; (y < ROWS) && (Array[y][0] != 0xFFFF); y++)
	{
		X = cxScreen*25;
		for (x = 0; Array[y][x] != 0xFFFF; x++)
		{
	 		I = Array[y][x];
			w = GetName();
			GetTextExtentPoint32(hdcMem, temp, w, &Size);
			Indiv[I].cx = (WORD)Size.cx;
			Indiv[I].X = X;
			X += Size.cx + 24;
		}
	}

//get descendants Indiv[i].X
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Loops[0] = '0';
LoopX = xPos+20;
LoopY = yPos;
endlessloop = 0;
begin2:
	for (y = MIDROW+1; (y < ROWS) && (Array[y][0] != 0xFFFF); y++)
	{
		prevRightchild = 0xFFFF;
		for (parentX = 0; Array[y-1][parentX] != 0xFFFF; parentX++)
		{
			if (Indiv[Array[y-1][parentX]].Child)
			{
				gotleftchild = FALSE;
				for (x = 0; Array[y][x] != 0xFFFF; x++)
				{
					if (Indiv[Array[y][x]].Parent == Array[y-1][parentX])
					{
						if (gotleftchild == FALSE)
						{
							gotleftchild = TRUE;
							Leftchild = x;
							Indiv[Array[y][x]].LeftChild = TRUE;
						}
						if (gotleftchild)
							Rightchild = x;
					}
				}
				if (gotleftchild)
				{
					if (Indiv[Array[y][Rightchild]].X != Indiv[Array[y][Leftchild]].X)
						Indiv[Array[y][Rightchild]].RightChild = TRUE;
					else
						Indiv[Array[y][Leftchild]].LeftChild = FALSE;
 					if (Rightchild > Leftchild)
						ChildLineLength = (Indiv[Array[y][Rightchild]].X + (Indiv[Array[y][Rightchild]].cx/2))
						 - (Indiv[Array[y][Leftchild]].X + (Indiv[Array[y][Leftchild]].cx/2));
					else
						ChildLineLength = 0;
					if (Indiv[Array[y-1][parentX]].Spouse)
						LinetoChildrenX = Indiv[Array[y-1][parentX]].X - 12;
					else
						LinetoChildrenX = Indiv[Array[y-1][parentX]].X + (Indiv[Array[y-1][parentX]].cx/2);
					LinefromChildrenX = Indiv[Array[y][Leftchild]].X + (Indiv[Array[y][Leftchild]].cx/2) + (ChildLineLength/2);

					if (LinetoChildrenX > LinefromChildrenX)
					{
						for (x = Leftchild; Array[y][x] != 0xFFFF; x++)//x <= Rightchild
							Indiv[Array[y][x]].X += LinetoChildrenX - LinefromChildrenX;//move children to the right
					}

					else if (LinetoChildrenX != LinefromChildrenX)
					{//move parents to the right & start over
						oldX = Indiv[Array[y-1][parentX]].X;
						////////////////////////////
						Indiv[Array[y-1][parentX]].X = LinefromChildrenX + 12;//move parent to right
						////////////////////////////
						newX = Indiv[Array[y-1][parentX]].X - oldX;
						for (s = 0; (s < MAXSPOUSES) && (Indiv[Array[y-1][parentX]].Spouseof[s]); s++)
						{
							spouseof = Indiv[Array[y-1][parentX]].Spouseof[s] & 0x7FFFFFFF;
							for (z = parentX-1; z != 0xFFFFFFFF; z--)
							{
								for (ws = 0; (ws < MAXSPOUSES) && (Indiv[Array[y-1][z]].Spouseof[ws]); ws++)
								{
									if ((Indiv[Array[y-1][z]].Spouseof[ws] & 0x7FFFFFFF) == spouseof)
									{
										for (v = 1; parentX-v != 0xFFFFFFFF; v++)
										{
											if (Indiv[Array[y-1][parentX-v]].Child)
											{//not parent's spouse, but with a child
												for (x = 1; x != v; x++)
													Indiv[Array[y-1][parentX-v+x]].X += newX;
												break;
											}
											for (ws = 0; (ws < MAXSPOUSES) && (Indiv[Array[y-1][parentX-v]].Spouseof[ws]); ws++)
											{
												if ((Indiv[Array[y-1][parentX-v]].Spouseof[ws] & 0x7FFFFFFF) == spouseof)
												{
													for (z = parentX-v; (z != 0xFFFFFFFF) && (Indiv[Array[y-1][z]].Child == 0); z--)
														;
													z++;
													for ( ; z != parentX; z++)
														Indiv[Array[y-1][z]].X += newX;
													goto x1;
												}
											}
										}
										goto x1;
									}
								}
							}
						}
						for (z = parentX-1; (z != 0xFFFFFFFF) && (Indiv[Array[y-1][z]].Child == 0); z--)
							;//if single parent
						z++;
						for (; z < parentX; z++)
							Indiv[Array[y-1][z]].X += newX;
x1:						for (z = parentX+1; Array[y-1][z] != 0xFFFF; z++)
							Indiv[Array[y-1][z]].X += newX;//move individuals-to-right-of-parent to right
						endlessloop++;
						if ((endlessloop % 10000 == 0) && (xPos) && (yPos))
						{
							Loops[0]++;
							hdc = GetDC(hwnd);
							TextOut(hdc, LoopX, LoopY, Loops, 12);
							ReleaseDC(NULL, hdc);
						}
						if (endlessloop < 80000)
							goto begin2;
						else
						{
							MessageBox(hwnd, TEXT("A loop didn't finish executing.\nThere must be too much data."), ERROR, MB_OK);
							highlighted = oldHighlighted;
							bs--;
							DestroyWindow(hwnd);
							return;
						}
					}//end of else if (LinetoChildrenX != LinefromChildrenX)
				}//end of if (gotleftchild)
			}
		}
	}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	SetCursor(hCursor);

	for (LastRow = MIDROW; (LastRow < ROWS) && (Array[LastRow][0] != 0xFFFF); LastRow++)
		;
	DependantMinX = 0xFFFFFFFF;
	for (y = MIDROW; y < LastRow; y++)
	{
		if (Indiv[Array[y][0]].X < DependantMinX)
		{
			DependantMinX = Indiv[Array[y][0]].X;
			row = (WORD)y;
		}
	}
	DependantMinX -= 50;

	for (y = MIDROW; y < LastRow; y++)
	{
		for (x = 0; Array[y][x] != 0xFFFF; x++)
		{
			Indiv[Array[y][x]].X -=	DependantMinX;
			Indiv[Array[y][x]].Flags |= 0x1000000;
		}
	}

//fill-in empty cols
	SmallestGap = 0xFFFFFFFF;
	y = row;//furthest-left row
	for (x = 0; Array[y][x] != 0xFFFF; x++)
	{
gaploop:
		z = Indiv[Array[y][x]].X + Indiv[Array[y][x]].cx + 24;
		if ((Array[y][x+1] == 0xFFFF) || (Indiv[Array[y][x+1]].X > z))
		{//if at a gap
			w = Indiv[Array[y][x]].X;
			for (row = MIDROW; row < LastRow; row++)
			{
				for (col = 0; (Array[row][col] != 0xFFFF) && (Indiv[Array[row][col]].X <= z); col++)
				{
					if ((Indiv[Array[row][col]].X + Indiv[Array[row][col]].cx + 24) > z)
					{
						x = col;
						y = row;
						goto gaploop;
					}
					else if (((Indiv[Array[row][col]].X + Indiv[Array[row][col]].cx + 24) > w)
						  && ((Indiv[Array[row][col]].X + Indiv[Array[row][col]].cx + 24) <= z)
						  && (Array[row][col+1] != 0xFFFF)
						  && ((Indiv[Array[row][col]].X + Indiv[Array[row][col]].cx + 24) == Indiv[Array[row][col+1]].X)
						  && ((Indiv[Array[row][col+1]].X + Indiv[Array[row][col+1]].cx + 24) > z))
					{
						x = col+1;
						y = row;
						goto gaploop;
					}
				}
			}
			//find the gap size to fill
			for (row = MIDROW; row < LastRow; row++)
			{
				Col[row] = 0xFFFFFFFF;
				for (col = 0; Array[row][col] != 0xFFFF; col++)
				{
					if (Indiv[Array[row][col]].X > z)
					{
						Col[row] = col;
						Gap = Indiv[Array[row][col]].X - z;
						if (SmallestGap > Gap)
						{
							SmallestGap = Gap;
							x = col;
							y = row;
						}
						break;
					}
				}
			}
			if (SmallestGap != 0xFFFFFFFF)
			{
				for (row = MIDROW; row < LastRow; row++)
				{
					for (col = Col[row]; Array[row][col] != 0xFFFF; col++)
					{
						if (Col[row] != 0xFFFFFFFF)
							Indiv[Array[row][col]].X -= SmallestGap;//fill the gap
					}
				}
			}
			else
				goto gapend;//normal exit
			SmallestGap = 0xFFFFFFFF;
			goto gaploop;
		}
	}
gapend:;

	HighlightedDependantX = Indiv[highlighted].X + (Indiv[highlighted].cx/2);
	if (HighlightedDependantX > HighlightedAncestorX)
	{
		z = HighlightedDependantX - HighlightedAncestorX;
		for (y = RowsUp; y < MIDROW; y++)
		{
			for (x = 0; Array[y][x] != 0xFFFF; x++)
			{
				Indiv[Array[y][x]].X +=	z;
			}
		}
	}
	else if (HighlightedAncestorX > HighlightedDependantX)
	{
		z = HighlightedAncestorX - HighlightedDependantX;
		for (y = MIDROW; y < LastRow; y++)
		{
			for (x = 0; Array[y][x] != 0xFFFF; x++)
			{
				Indiv[Array[y][x]].X +=	z;
			}
		}
	}

	Width = 0;
	for (y = RowsUp; y < LastRow; y++)
	{
		for (x = 0; Array[y][x] != 0xFFFF; x++)
		{
			if (Width < (int)Indiv[Array[y][x]].X)
				Width = Indiv[Array[y][x]].X;
		}
	}
	Width += 150;
	Height = (LastRow - RowsUp + 1) * YSpacing;

	if (rect.bottom)
		y = rect.bottom;
	else
		y = cyScreen;
	if (rect.right)
		x = rect.right;
	else
		x = cxScreen;
	if (Height > (int)y)
		Top = Height - y;
	else
		Top = 0;
	if (Width > (int)x)
		Left = Width - x;
	else
		Left = 0;
	if ((Indiv[highlighted].X + Indiv[highlighted].cx) > x)
		xLoc = Indiv[highlighted].X + Indiv[highlighted].cx - (x/2);
	else
		xLoc = 0;
	z = (MIDROW - RowsUp) * YSpacing;
	if (z > (DWORD)Top)
		yLoc = Top;
	else
		yLoc = z;
	xPrevious = -1;

	FillhdcMem();
	arrayfilled = TRUE;
}


void FillhdcMem(void)
{
	if (LastIndiv == 0)
		return;
	FillRect(hdcMem, &rectMem, hBrush);
	HighlightedRect.left = Indiv[Array[MIDROW][0]].X - xLoc - 5;
	HighlightedRect.right = Indiv[Array[MIDROW][0]].X - xLoc + Indiv[Array[MIDROW][0]].cx + 5;
	HighlightedRect.top = ((MIDROW-RowsUp+1)*YSpacing) - yLoc - 5;
	HighlightedRect.bottom = ((MIDROW-RowsUp+1)*YSpacing) - yLoc + Z + 5;
	FillRect(hdcMem, &HighlightedRect, hHighlightedBrush);
	for (Y = -yLoc, y = RowsUp; y < LastRow; y++)
	{
		Y += YSpacing;
		gotleftchild = FALSE;
		for (x = 0; Array[y][x] != 0xFFFF; x++)
		{
			I = Array[y][x];
			if (((Indiv[I].X + Indiv[I].cx + 5) >= (DWORD)xLoc) && ((Indiv[I].X - 5) <= (DWORD)(xLoc + cxScreen)))
			{//if box is on-screen
				X = Indiv[I].X - xLoc;
				Size.cx = Indiv[I].cx;
				w = GetName();
				TextOut(hdcMem, X, Y, temp, w);
				bd = 0;
				if (Indiv[I].Birth)
				{
					Birth = &Buf[Indiv[I].Birth];
					for (w = 0; (Birth[w] != '\r') && (Birth[w] != '\n'); w++)
					{
						if ((Birth[w] >= '0') && (Birth[w] <= '9') && (Birth[w+1] >= '0') && (Birth[w+1] <= '9') && (Birth[w+2] >= '0') && (Birth[w+2] <= '9') && (Birth[w+3] >= '0') && (Birth[w+3] <= '9'))
						{
							temp[bd++] = Birth[w];
							temp[bd++] = Birth[w+1];
							temp[bd++] = Birth[w+2];
							temp[bd++] = Birth[w+3];
							break;
						}
					}
				}
				if (Indiv[I].Death)
				{
					Death = &Buf[Indiv[I].Death];
					for (w = 0; (Death[w] != '\r') && (Death[w] != '\n'); w++)
					{
						if ((Death[w] >= '0') && (Death[w] <= '9') && (Death[w+1] >= '0') && (Death[w+1] <= '9') && (Death[w+2] >= '0') && (Death[w+2] <= '9') && (Death[w+3] >= '0') && (Death[w+3] <= '9'))
						{
							temp[bd++] = '-';
							temp[bd++] = Death[w];
							temp[bd++] = Death[w+1];
							temp[bd++] = Death[w+2];
							temp[bd++] = Death[w+3];
							break;
						}
					}
				}
				if (bd)
				{
x24:				GetTextExtentPoint32(hdcMem, temp, bd, &Size2);
					if (Size2.cx < (Indiv[I].cx+8))
						TextOut(hdcMem, X, Y+Size.cy, temp, bd);
					else if (bd > 4)
					{
						bd--;
						goto x24;//make it fit in box
					}
				}
				if ((photo) && (Indiv[I].Flags & 0x100000))//there's a photo of him/her
				{
					SetTextColor(hdcMem, RED);
					TextOut(hdcMem, X+Size.cx-2, Y+Size.cy+5, TEXT("P"), 1);
					SetTextColor(hdcMem, BLACK);
				}
				//draw box:
				MoveToEx(hdcMem, X-5, Y-5, NULL);
				LineTo(hdcMem, X-5, Y+5+Z);
				LineTo(hdcMem, X+5+Size.cx, Y+5+Z);
				LineTo(hdcMem, X+5+Size.cx, Y-5);
				LineTo(hdcMem, X-5, Y-5);
				if (Indiv[I].Flags & 0x10000000)//duplicate individual (an individual married a cousin)
				{
					boxRect.left = X-4;
					boxRect.top = Y+Z-4;
					boxRect.right = X+5;
					boxRect.bottom = Y+4+Z;
					FillRect(hdcMem, &boxRect, hYellowBrush);
				}
				if (Indiv[I].Childof != 0)
				{//draw line up from all children
					MoveToEx(hdcMem, X + (Indiv[I].cx/2), Y-5, NULL);
					LineTo(hdcMem, X + (Indiv[I].cx/2), Y-12);
				}
				if (y < MIDROW)
				{
					if ((Array[y][x+1] != 0xFFFF) && (Indiv[I].Spouse == Array[y][x+1]))
					{//draw line down to child
						z = X + Size.cx + 5;
						SpouseLineLen = (Indiv[Array[y][x+1]].X - xLoc - 5) - z;
						MoveToEx(hdcMem, z + (SpouseLineLen/2), Y+Size.cy+2, NULL);
						LineTo(hdcMem, z + (SpouseLineLen/2), Y+YSpacing-5);//Y+Size.cy+30
					}
					else if ((y < MIDROW) && (Indiv[I].Child) && (Indiv[I].Spouse == 0))
					{//draw line down from single parent
						MoveToEx(hdcMem, X + (Size.cx/2), Y+Z+5, NULL);
						LineTo(hdcMem, X + (Size.cx/2), Y+YSpacing-5);//Y+Size.cy+30
					}
				}

				if (y >= MIDROW)
				{
					if ((Indiv[I].Parent) && (y != MIDROW))
					{//draw line up from descendants
						MoveToEx(hdcMem, X+(Size.cx/2), Y-5, NULL);
						LineTo(hdcMem, X+(Size.cx/2), Y-18);
					}
					if ((Indiv[I].Flags & 8) && (y != MIDROW))
					{//draw short line up from duplicate descendant
						MoveToEx(hdcMem, X+(Size.cx/2), Y-5, NULL);
						LineTo(hdcMem, X+(Size.cx/2), Y-12);
					}
					if (Indiv[I].Child)
					{//draw line down
						if (Indiv[I].Spouse)
						{
							MoveToEx(hdcMem, X-12, Y+Size.cy+2, NULL);
							LineTo(hdcMem, X-12, Y+Z+17);
						}
						else
						{
							MoveToEx(hdcMem, X + (Size.cx/2), Y+Z+5, NULL);
							LineTo(hdcMem, X + (Size.cx/2), Y+Z+17);
						}
					}
				}
			}//end of if box is on-screen
			else if (y < MIDROW)//and Indiv[I].X not on-screen
			{
				if ((Indiv[I].Spouse == Array[y][x+1]) && (Array[y][x+1] != 0xFFFF))
				{
					if ((Array[y][x+1] != 0xFFFF) && (((Indiv[Array[y][x+1]].X - 5) > (DWORD)xLoc) && (Indiv[Array[y][x+1]].X - 5) < (DWORD)(xLoc + cxScreen)))
					{//draw spouse lines if spouse is on-screen
						MoveToEx(hdcMem, 0, Y+Size.cy+2, NULL);
						LineTo(hdcMem, Indiv[Array[y][x+1]].X - xLoc - 5, Y+Size.cy+2);
						MoveToEx(hdcMem, 0, Y+Size.cy-2, NULL);
						LineTo(hdcMem, Indiv[Array[y][x+1]].X - xLoc - 5, Y+Size.cy-2);
					}
					SpouseLineLen = (Indiv[Array[y][x+1]].X - 5) - (Indiv[I].X + Indiv[I].cx);
					if (((Indiv[Array[y][x+1]].X - 5 - (SpouseLineLen/2)) > (DWORD)xLoc) && ((Indiv[Array[y][x+1]].X - 5 - (SpouseLineLen/2)) < (DWORD)(xLoc + cxScreen)))
					{//line down to child
						int addative = 2;
						if (SpouseLineLen & 1)
							addative++;
//						MoveToEx(hdcMem, addative + Indiv[Array[y][x+1]].X - xLoc - 5 - (SpouseLineLen/2), Y+Size.cy+2, NULL);
//						LineTo(hdcMem, addative + Indiv[Array[y][x+1]].X - xLoc - 5 - (SpouseLineLen/2), Y+YSpacing-5);//Y+Size.cy+30
						MoveToEx(hdcMem, addative + Indiv[I].X + Indiv[I].cx + (SpouseLineLen/2) - xLoc, Y+Size.cy+2, NULL);
						LineTo(hdcMem, addative + Indiv[I].X + Indiv[I].cx + (SpouseLineLen/2) - xLoc, Y+YSpacing-5);//Y+Size.cy+30
					}
				}
			}
			if (x && ((y >= MIDROW) && (Indiv[I].Spouse))
			 || ((y < MIDROW) && (Indiv[I].Spouse == Array[y][x-1])))
			{//draw spouse lines to left
				if ((Indiv[I].X - 5) > (DWORD)(xLoc + cxScreen))
				{
					if ((x) && ((Indiv[Array[y][x-1]].X + Indiv[Array[y][x-1]].cx + 5) > (WORD)xLoc))
					{//from right to on-screen
						MoveToEx(hdcMem, cxScreen, Y+Size.cy-2, NULL);
						LineTo(hdcMem, Indiv[Array[y][x-1]].X - xLoc + Indiv[Array[y][x-1]].cx + 5, Y+Size.cy-2);
						MoveToEx(hdcMem, cxScreen, Y+Size.cy+2, NULL);
						LineTo(hdcMem, Indiv[Array[y][x-1]].X - xLoc + Indiv[Array[y][x-1]].cx + 5, Y+Size.cy+2);
					}
					else
					{
						MoveToEx(hdcMem, cxScreen, Y+Size.cy-2, NULL);
						LineTo(hdcMem, 0, Y+Size.cy-2);
						MoveToEx(hdcMem, cxScreen, Y+Size.cy+2, NULL);
						LineTo(hdcMem, 0, Y+Size.cy+2);
					}
				}
				else if (((Indiv[I].X - 5) > (DWORD)xLoc)
					  && ((Indiv[I].X - 5) < (DWORD)(xLoc + cxScreen)))
				{//from on-screen
					if ((Indiv[Array[y][x-1]].X + Indiv[Array[y][x-1]].cx + 5) > (DWORD)xLoc)
					{//on-screen to on-screen
						MoveToEx(hdcMem, X-5, Y+Size.cy-2, NULL);
						LineTo(hdcMem, Indiv[Array[y][x-1]].X - xLoc + Indiv[Array[y][x-1]].cx + 5, Y+Size.cy-2);
						MoveToEx(hdcMem, X-5, Y+Size.cy+2, NULL);
						LineTo(hdcMem, Indiv[Array[y][x-1]].X - xLoc + Indiv[Array[y][x-1]].cx + 5, Y+Size.cy+2);
					}
					else//if ((Indiv[Array[y][x-1]].X + Indiv[Array[y][x-1]].cx + 5) < xLoc))
					{//from on-screen to left off-screen
						MoveToEx(hdcMem, X-5, Y+Size.cy-2, NULL);
						LineTo(hdcMem, 0, Y+Size.cy-2);
						MoveToEx(hdcMem, X-5, Y+Size.cy+2, NULL);
						LineTo(hdcMem, 0, Y+Size.cy+2);
					}
				}
			}

			if (y >= MIDROW)
			{
				if ((Indiv[I].LeftChild) && (gotleftchild == FALSE))
				{//draw sibling lines
					gotleftchild = TRUE;
					if ((Indiv[I].X + (Indiv[I].cx/2)) <= (DWORD)xLoc)
						Leftchild = 0;
					else if (((Indiv[I].X + (Indiv[I].cx/2)) > (DWORD)xLoc) && ((Indiv[I].X + (Indiv[I].cx/2)) < (DWORD)(xLoc + cxScreen)))
						Leftchild = Indiv[I].X - xLoc + (Indiv[I].cx/2);
					else
						Leftchild = 0xFFFFFFFF;//flag that it's to right of screen
				}
				if ((Indiv[I].RightChild) && (gotleftchild))
				{//draw sibling lines
					gotleftchild = FALSE;
					if ((Leftchild != 0xFFFFFFFF) && ((Indiv[I].X + (Indiv[I].cx/2)) >= (DWORD)(xLoc + cxScreen)) && (Indiv[I].LeftChild == FALSE))
					{
						MoveToEx(hdcMem, Leftchild, Y - 17, NULL);//connect siblings
						LineTo(hdcMem, cxScreen, Y - 17);
					}
					else if (((Indiv[I].X + (Indiv[I].cx/2)) > (DWORD)xLoc) && ((Indiv[I].X + (Indiv[I].cx/2)) < (DWORD)(xLoc + cxScreen)))
					{
						MoveToEx(hdcMem, Leftchild, Y - 17, NULL);//connect siblings
						LineTo(hdcMem, Indiv[I].X - xLoc + (Indiv[I].cx/2) + 1, Y - 17);
					}
				}
			}
		}
	}

	InvalidateRect(hwnd, &rect, FALSE);
	UpdateWindow(hwnd);
	if (updateindiv)
	{
		updateindiv = FALSE;
		preditit = TRUE;
		hwndIndiv = CreateDialog(hInst, TEXT("INDIVIDUAL"), hwnd, IndivProc);
		indivbox = FALSE;
	}
}

DWORD GetName(void)
{//abnornal name: Valentine/HOLLINGSWORTH/Sr, (came to America 1682)..
	int x;

	NameX = Indiv[I].Name;
	for (x = 0, w = NameX; (x < 255) && (Buf[w] != '\n') && (Buf[w] != ' ') && (Buf[w] != '/'); w++, x++)
		temp[x] = Buf[w];
	if (Buf[w] == '/')
		temp[x] = ' ';
	else if ((x == 255) || (Buf[w] == '\n'))
		x = 0;
	else
		temp[x++] = ' ';
	for (z = w; (Buf[z] != '/') && (z < (NameX+255)); z++)
		;
	z++;//past '/'
	for ( ; Buf[z] != '/'; x++, z++)
	{
		temp[x] = Buf[z];
/*
		if ((temp[x] >= 'a') && (temp[x] <= 'z') && ((temp[x] != 'c') || (temp[x-1] != 'M')))
			temp[x] &= 0xDF;
		else if (temp[x] == -15)//ñ 
			temp[x] = 'N';
		else if (temp[x] == -31)//á
			temp[x] = 'A';
		else if (temp[x] == -23)//é
			temp[x] = 'E';
		else if (temp[x] == -19)//í
			temp[x] = 'I';
		else if (temp[x] == -13)//ó
			temp[x] = 'O';
		else if (temp[x] == -6)//ú
			temp[x] = 'U';
*/
	}
	temp[x] = 0;
	return x;
}

int CALLBACK ListProc(HWND hwndListDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	static int dlgWidth;
	static TCHAR IndivInfo[] = TEXT("Show Individual's &Info");
	static TCHAR FamTree[] = TEXT("Show Individual's &Family Tree");
	static HWND hwndButton;

	switch (message)
	{
	case WM_INITDIALOG:
		list = TRUE;
		_snwprintf(temp, 256, TEXT("List of %i Individuals"), RealLastIndiv-1);
		SetWindowText(hwndListDlg, temp);
		index = -1;
		HighlightedName[0] = 0;//flag
		GetWindowRect(hwndListDlg, &dlgRect);
		dlgWidth = dlgRect.right-dlgRect.left;
		MoveWindow(hwndListDlg, cxScreen-dlgWidth-10, IndivTop, dlgWidth, cyScreen-30, TRUE);
		hwndList = GetDlgItem(hwndListDlg, IDC_LIST1);
		hwndButton = GetDlgItem(hwndListDlg, IDC_BUTTON1);
		if (showindividual)
			SendMessage(hwndButton, WM_SETTEXT, 0, (LPARAM)FamTree);
		else
			SendMessage(hwndButton, WM_SETTEXT, 0, (LPARAM)IndivInfo);
		GetWindowRect(hwndList, &dlgRect);
		MoveWindow(hwndList, 0, 70, dlgWidth-6, cyScreen-130, TRUE);
		SendMessage(hwndList, WM_SETFONT, (WPARAM)hFont, TRUE);

		SendMessage(hwndList, LB_INITSTORAGE, RealLastIndiv, RealLastIndiv*40);
		for (I = 1; I < RealLastIndiv; I++)
		{
			if (Indiv[I].Name == 0)
				continue;
			NameX = Indiv[I].Name;
			for (z = NameX; (Buf[z] != '/') && (z < (NameX+255)); z++)
			{
				if ((Buf[z] == '\n') || (Buf[z] == '\r'))
				{
					_snwprintf(Error, 512, TEXT("Missing /NAME/ after 0 @I%u@ INDI line\nin %s\n(which can be edited in Notepad)"), Indiv[I].Num, FullFilename);
					MessageBox(hwnd, Error, ERROR, MB_OK);
					DestroyWindow(hwnd);
					return 0;
				}
			}
			z++;//past '/'
			for (w = 0; Buf[z] != '/'; w++, z++)
			{
				temp[w] = Buf[z];
/*
				if ((temp[w] >= 'a') && (temp[w] <= 'z') && ((temp[w] != 'c') || (temp[w-1] != 'M')))
					temp[w] &= 0xDF;
				else if (temp[w] == -15)//ñ 
					temp[w] = 'N';
				else if (temp[w] == -31)//á
					temp[w] = 'A';
				else if (temp[w] == -23)//é
					temp[w] = 'E';
				else if (temp[w] == -19)//í
					temp[w] = 'I';
				else if (temp[w] == -13)//ó
					temp[w] = 'O';
				else if (temp[w] == -6)//ú
					temp[w] = 'U';
*/
			}
			temp[w++] = ',';
			temp[w++] = ' ';
			for (z = NameX; (Buf[z] != '/') && (z < (NameX+255)); w++, z++)
				temp[w] = Buf[z];

			if (Indiv[I].Birth)
			{
				temp[w++] = ' ';
				temp[w++] = 'b';
				temp[w++] = '.';
				Birth = &Buf[Indiv[I].Birth];
				for (z = 0; (Birth[z] != '\r') && (Birth[z] != '\n'); z++)
				{
					if ((Birth[z] >= '0') && (Birth[z] <= '9') && (Birth[z+1] >= '0') && (Birth[z+1] <= '9') && (Birth[z+2] >= '0') && (Birth[z+2] <= '9') && (Birth[z+3] >= '0') && (Birth[z+3] <= '9'))
					{
						temp[w++] = Birth[z++];
						temp[w++] = Birth[z++];
						temp[w++] = Birth[z++];
						temp[w++] = Birth[z++];
						break;
					}
				}
			}
			y = _snwprintf(Error, 512, TEXT("  [%i]"), Indiv[I].Num);
			for (x = 0; x < y; x++, w++)
				temp[w] = Error[x];
			temp[w] = 0;
			SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)temp);
			if ((highlighted != 0xFFFF) && (I == highlighted))
			{
				for (x = 0; (x < 256) && (temp[x] != 0); x++)
					HighlightedName[x] = temp[x];
				HighlightedName[x] = 0;
			}
		}
		if (HighlightedName[0] != 0)
		{
			index = SendMessage(hwndList, LB_FINDSTRINGEXACT, -1, (LPARAM)(LPCSTR)HighlightedName);
			SendMessage(hwndList, LB_SETCURSEL, index, 0);
			if (fromnewlink == FALSE)
				IndivNum = highlighted;//for IndivProc
			if (showindividual)
			{
				if (hwndIndiv)
				{
					if (DestroyWindow(hwndIndiv))
						hwndIndiv = NULL;
				}
				hwndIndiv = CreateDialog(hInst, TEXT("INDIVIDUAL"), hwnd, IndivProc);
				indivbox = TRUE;
			}
		}
		SetFocus(hwndList);
		pListProc = (WNDPROC)SetWindowLong(hwndList, GWL_WNDPROC, (LONG)EditListProc);
		if (undone)
		{
			undone = FALSE;
			FindFirstFile(FullFilename, &fd);
			li1 = *(ULARGE_INTEGER*)&ft;
			li1.LowPart = fd.ftLastWriteTime.dwLowDateTime;
			li1.HighPart = fd.ftLastWriteTime.dwHighDateTime;
			FindFirstFile(BackupFilename, &fd);
			li2 = *(ULARGE_INTEGER*)&ft;
			li2.LowPart = fd.ftLastWriteTime.dwLowDateTime;
			li2.HighPart = fd.ftLastWriteTime.dwHighDateTime;
			if (li1.QuadPart > li2.QuadPart)
				MessageBox(hwndListDlg, TEXT("Latest data"), TEXT(""), MB_OK);
			else
				MessageBox(hwndListDlg, TEXT("Older data"), TEXT(""), MB_OK);
		}
		break;

	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDC_BUTTON1:
			if (index != -1)
			{
				if (showindividual)
				{
					showindividual = FALSE;
					InitializeAgain();			
					for (i = 1; i < LastIndiv; i++)
					{
						if (Indiv[i].Num == Num)
						{
							oldHighlighted = highlighted;
							highlighted = i;
							IndivNum = highlighted;
							InitializeAgain();			
							break;
						}
					}
					SendMessage(hwndButton, WM_SETTEXT, 0, (LPARAM)IndivInfo);
					if (DestroyWindow(hwndIndiv))
						hwndIndiv = NULL;
					SetFocus(hwndList);
				}
				else
				{
					showindividual = TRUE;
					SendMessage(hwndButton, WM_SETTEXT, 0, (LPARAM)FamTree);
					if (hwndIndiv)
					{
						if (DestroyWindow(hwndIndiv))
							hwndIndiv = NULL;
					}
					hwndIndiv = CreateDialog(hInst, TEXT("INDIVIDUAL"), hwnd, IndivProc);
					indivbox = TRUE;
					SetFocus(hwndList);
				}
			}
			else
				MessageBox(hwndList, TEXT("First highlight an individual"), TEXT(""), MB_OK);
			break;

		case IDC_LIST1:
			if (HIWORD (wParam) == LBN_DBLCLK)
				SendMessage(hwndListDlg, WM_COMMAND, (WPARAM)IDOK, 0);

			else if ((HIWORD (wParam) == LBN_SELCHANGE) && (fromnewlink == FALSE))
			{
				if (index == -1)
				{
					IndivNum = 0;//flag
					if (hwndIndiv)
					{
						if (DestroyWindow(hwndIndiv))
							hwndIndiv = NULL;
					}
					hwndIndiv = CreateDialog(hInst, TEXT("INDIVIDUAL"), hwnd, IndivProc);
					indivbox = TRUE;
					SetFocus(hwndList);
				}
				index = SendMessage(hwndList, LB_GETCURSEL, 0, 0);
				SendMessage(hwndList, LB_GETTEXT, index, (LPARAM)IndivName);
				for (x = 0; IndivName[x] != '['; x++)
					;
				x++;
				for (y = x, Num = 0; IndivName[y] != ']'; y++)
					Num = (Num * 10) + (IndivName[y] - '0');
				if (showindividual == FALSE)
				{
					for (i = 1; i < LastIndiv; i++)
					{
						if (Indiv[i].Num == Num)
						{
							oldHighlighted = highlighted;
							highlighted = i;
							InitializeAgain();			
							break;
						}
					}
				}
				else
				{
					if (indivbox == FALSE)
					{
						if (DestroyWindow(hwndIndiv))
							hwndIndiv = NULL;
					}
					if (hwndIndiv == NULL)
					{
						hwndIndiv = CreateDialog(hInst, TEXT("INDIVIDUAL"), hwnd, IndivProc);
						indivbox = TRUE;
						SetFocus(hwndList);
					}
					for (i = 1; i < LastIndiv; i++)
					{
						if (Indiv[i].Num == Num)
						{
							if (Indiv[i].Name)
							{
								NameX = Indiv[i].Name;
								for (x = NameX, y = 0; (Buf[x] != '\r') && (Buf[x] != '\n'); x++)
//									if (Buf[x] != '/')
										Name[y++] = Buf[x];
								Name[y] = 0;
								Namend = x;
//								ch = Buf[x];
//								Buf[x] = 0;
//								SendDlgItemMessage(hwndIndiv, IDC_EDIT1, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)&Buf[Indiv[i].Name]);
								SendDlgItemMessage(hwndIndiv, IDC_EDIT1, WM_SETTEXT, 0, (LPARAM)(LPCTSTR) Name);
//								Buf[x] = ch;
							}
							else
								MessageBox(hwnd, TEXT("Tell jdmcox@jdmcox about this."), TEXT("Oops"), MB_OK);
							if (Indiv[i].Sex == 1)//male
								x = SendDlgItemMessage(hwndIndiv, IDC_EDIT3, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)TEXT("Mr"));
							else if (Indiv[i].Sex == 0xFFFF)//female
								SendDlgItemMessage(hwndIndiv, IDC_EDIT3, WM_SETTEXT, 0, (LPARAM)TEXT("Ms"));
							else
								SendDlgItemMessage(hwndIndiv, IDC_EDIT2, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)Blank);
							if (Indiv[i].Birth)
							{
								Birth = &Buf[Indiv[i].Birth];
								for (x = 0; (Birth[x] != '\r') && (Birth[x] != '\n'); x++)
									;
								ch = Birth[x];
								Birth[x] = 0;
								SendDlgItemMessage(hwndIndiv, IDC_EDIT2, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)&Buf[Indiv[i].Birth]);
								Birth[x] = ch;
							}
							else
								SendDlgItemMessage(hwndIndiv, IDC_EDIT2, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)Blank);
							if (Indiv[i].BirthLoc)
							{
								BirthLoc = &Buf[Indiv[i].BirthLoc];
								for (x = 0; (BirthLoc[x] != '\r') && (BirthLoc[x]!= '\n'); x++)
									;
								ch = BirthLoc[x];
								BirthLoc[x] = 0;
								SendDlgItemMessage(hwndIndiv, IDC_EDIT5, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)&Buf[Indiv[i].BirthLoc]);
								BirthLoc[x] = ch;
							}
							else
								SendDlgItemMessage(hwndIndiv, IDC_EDIT5, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)Blank);
							if (Indiv[i].Death)
							{
								Death = &Buf[Indiv[i].Death];
								for (x = 0; (Death[x] != '\r') && (Death[x]!= '\n'); x++)
									;
								ch = Death[x];
								Death[x] = 0;
								SendDlgItemMessage(hwndIndiv, IDC_EDIT4, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)&Buf[Indiv[i].Death]);
								Death[x] = ch;
							}
							else
								SendDlgItemMessage(hwndIndiv, IDC_EDIT4, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)Blank);
							if (Indiv[i].DeathLoc)
							{
								DeathLoc = &Buf[Indiv[i].DeathLoc];
								for (x = 0; (DeathLoc[x] != '\r') && (DeathLoc[x]!= '\n'); x++)
									;
								ch = DeathLoc[x];
								DeathLoc[x] = 0;
								SendDlgItemMessage(hwndIndiv, IDC_EDIT6, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)&Buf[Indiv[i].DeathLoc]);
								DeathLoc[x] = ch;
							}
							else
								SendDlgItemMessage(hwndIndiv, IDC_EDIT6, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)Blank);
							//////////
							IndivNum = i;
							GetData();
							//////////
							SendDlgItemMessage(hwndIndiv, IDC_EDIT7, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)BigNote);

//							_snwprintf(temp, "  (number %i in Gedcom file)", Indiv[IndivNum].Num);
//							SetWindowText(hwndIndiv, temp);
							SetWindowText(hwndIndiv, Name);
						}
					}
				}
			}
			break;

		case IDOK:
			list = FALSE;
			index = SendMessage(hwndList, LB_GETCURSEL, 0, 0);
			SendMessage(hwndList, LB_GETTEXT, index, (LPARAM)IndivName);
			for (x = 0; (IndivName[x] != 0) && (IndivName[x] != '['); x++)
				;
			if (IndivName[x] == 0)
				break;
			x++;
			for (y = x, Num = 0; IndivName[y] != ']'; y++)
				Num = (Num * 10) + (IndivName[y] - '0');
			for (i = 1; i < LastIndiv; i++)
			{
				if (Indiv[i].Num == Num)
				{
					if (fromnewlink)
					{
						fromnewlink = FALSE;
						if (hwndIndiv)
						{
							if (DestroyWindow(hwndIndiv))
								hwndIndiv = NULL;
						}
						EndDialog (hwndListDlg, TRUE);//trick
						hwndListDlg = NULL;
						return TRUE;
					}
					else
					{
						oldHighlighted = highlighted;
						highlighted = i;
						if (bs < 511)
							bs++;
						if (Backspace[bs] != -1)
							for ( ; (bs < 511) && (Backspace[bs] != -1); bs++)
								;
						Backspace[bs] = i;
					}
					if (hwndIndiv)
					{
						if (DestroyWindow(hwndIndiv))
							hwndIndiv = NULL;
					}
					if (hwndListDlg)
					{
						if (DestroyWindow(hwndListDlg))
							hwndListDlg = NULL;
					}
					if (showindividual)
						InitializeAgain();
					return TRUE;
				}
			}
			break;

		case IDCANCEL:
			list = FALSE;
			if (fromnewlink)
			{
				fromnewlink = FALSE;
				EndDialog (hwndListDlg, FALSE);//trick
				hwndListDlg = NULL;
				return FALSE;
			}
			if (hwndIndiv)
			{
				if (DestroyWindow(hwndIndiv))
					hwndIndiv = NULL;
			}
			if (DestroyWindow(hwndListDlg))
				hwndList = NULL;
			return FALSE;
		}
	}
	return FALSE;
}

int CALLBACK IndivProc(HWND hwndIndiv, UINT message, WPARAM wParam, LPARAM lParam)
{
	static TCHAR tempFamc[256];
	static HWND hwndAsterisk, hwndShowPhoto, hwndRemovePhoto, hwndAdoptive;

	switch (message)
	{
	case WM_INITDIALOG:
//		if (hwndPhoto)
//		{
//			DestroyWindow(hwndPhoto);
//			hwndPhoto = NULL;
//		}
//		if (mouseover == PHOTO)
//		{
//			gotmouseover = FALSE;
//			mouseover = NONE;
//			InvalidateRect(hwnd, &rect, FALSE);
//		}
		IndivNumber = Indiv[IndivNum].Num;
		dontupdateindiv = FALSE;
		newspouse = newchild = newfather = newmother = FALSE;
		hwndName = GetDlgItem(hwndIndiv, IDC_EDIT1);
		hwndBirth = GetDlgItem(hwndIndiv, IDC_EDIT2);
		hwndSex = GetDlgItem(hwndIndiv, IDC_EDIT3);
		hwndDeath = GetDlgItem(hwndIndiv, IDC_EDIT4);
		hwndBirthLoc = GetDlgItem(hwndIndiv, IDC_EDIT5);
		hwndDeathLoc = GetDlgItem(hwndIndiv, IDC_EDIT6);
		hwndNote = GetDlgItem(hwndIndiv, IDC_EDIT7);
		hwndAsterisk = GetDlgItem(hwndIndiv, IDC_EDIT8);
		hwndRemovePhoto = GetDlgItem(hwndIndiv, IDC_BUTTON13);
		hwndShowPhoto = GetDlgItem(hwndIndiv, IDC_BUTTON14);
		hwndAdoptive = GetDlgItem(hwndIndiv, IDC_BUTTON12);
		if (IndivNum == 0)
			break;
		if (Indiv[IndivNum].Sex == 1)//male
			SetWindowText(hwndSex, TEXT("Mr"));
		else if (Indiv[IndivNum].Sex == 0xFFFF)
			SetWindowText(hwndSex, TEXT("Ms"));
		else
			SetWindowText(hwndSex, Blank);

		if (Indiv[IndivNum].Flags & 0x100000)
		{
			SetWindowText(hwndShowPhoto, TEXT("Show &Photo"));
			ShowWindow(hwndRemovePhoto, SW_SHOW);
		}
		else
			SetWindowText(hwndShowPhoto, TEXT("Link &Photo"));

		if (Indiv[IndivNum].Flags & 0x10000)
			ShowWindow(hwndAdoptive, SW_SHOW);
		NameX = Indiv[IndivNum].Name;
		for (x = NameX, y = 0; (x != fileSize) && (Buf[x] != '\r') && (Buf[x]!= '\n'); x++)
//			if (Buf[x] != '/')
			Name[y++] = Buf[x];
		Name[y] = 0;
		Namend = x;
		ch = Buf[x];
		SetWindowText(hwndName, Name);
		for (x = 0, y = 0; Name[x] != 0; x++)
			if (Name[x] != '/')
				Name1[y++] = Name[x];
		Name1[y] = 0;
		SetWindowText(hwndIndiv, Name1);
		if (Indiv[IndivNum].Birth)
		{
			Birth = &Buf[Indiv[IndivNum].Birth];
			for (x = 0, y = 0; (y < 256) && (Birth[x] != '\r') && (Birth[x] != '\n'); x++, y++)
				BirthDeath[y] = Birth[x];
			if (Indiv[IndivNum].Flags & 1)
				BirthDeath[y++] = '*';
			BirthDeath[y] = 0;
			SetWindowText(hwndBirth, BirthDeath);
		}
		else
			SetWindowText(hwndBirth, Blank);
		if (Indiv[IndivNum].BirthLoc)
		{
			BirthLoc = &Buf[Indiv[IndivNum].BirthLoc];
			for (x = 0, y = 0; (y < 256) && (BirthLoc[x] != '\r') && (BirthLoc[x]!= '\n'); x++, y++)
				BirthDeath[y] = BirthLoc[x];
			if (Indiv[IndivNum].Flags & 0x10)
				BirthDeath[y++] = '*';
			BirthDeath[y] = 0;
			SetWindowText(hwndBirthLoc, BirthDeath);
		}
		else
			SetWindowText(hwndBirthLoc, Blank);
		if (Indiv[IndivNum].Death)
		{
			Death = &Buf[Indiv[IndivNum].Death];
			for (x = 0, y = 0; (y < 256) && (Death[x] != '\r') && (Death[x]!= '\n'); x++, y++)
				BirthDeath[y] = Death[x];
			if (Indiv[IndivNum].Flags & 0x100)
				BirthDeath[y++] = '*';
			BirthDeath[y] = 0;
			SetWindowText(hwndDeath, BirthDeath);
		}
		else
			SetWindowText(hwndDeath, Blank);

		if (Indiv[IndivNum].DeathLoc)
		{
			DeathLoc = &Buf[Indiv[IndivNum].DeathLoc];
			for (x = 0, y = 0; (y < 256) && (DeathLoc[x] != '\r') && (DeathLoc[x]!= '\n'); x++, y++)
				BirthDeath[y] = DeathLoc[x];
			if (Indiv[IndivNum].Flags & 0x1000)
				BirthDeath[y++] = '*';
			BirthDeath[y] = 0;
			SetWindowText(hwndDeathLoc, BirthDeath);
		}
		else
			SetWindowText(hwndDeathLoc, Blank);
		if ((Indiv[IndivNum].Flags) &&  (Indiv[IndivNum].Flags < 0x10000))
			SetWindowText(hwndAsterisk, TEXT("* More than one Birth/Death Date/Place in Gedcom file"));
		//////////
		GetData();
		//////////
		SetWindowText(hwndNote, BigNote);
		break;


	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case HELP:
			MessageBox(hwndIndiv, NamesDates, TEXT("Names and Dates"), MB_OK);
			MessageBox(hwndIndiv, PhotoHelp, TEXT("Photos"), MB_OK);
			MessageBox(hwndIndiv, AlternateParents, TEXT("Alternate Parents"), MB_OK);
			break;

		case IDC_BUTTON13://Remove photo link
			if (Indiv[IndivNum].Flags & 0x100000)//really not necessary
			{//if photo exists
//				GetPhotoFileName();
				hPhotoFile = CreateFile(SimpleFamilyTreePhotosTxt, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL);
				if (hPhotoFile != INVALID_HANDLE_VALUE)
				{
					DWORD x2 = 0;

					if (PhotoFileSize = GetFileSize(hPhotoFile, NULL))
					{
						utf = (BYTE*)malloc(PhotoFileSize);
						ReadFile(hPhotoFile, utf, PhotoFileSize, &dwBytesRead, NULL);
						PhotoBuf = (TCHAR*)malloc(sizeof(TCHAR)*PhotoFileSize);
						if ((utf[0] == 0xEF) && (utf[1] == 0xBB) && (utf[2] == 0xBF))
							x = 3;
						else
							x = 0;
						for (y = 0; x < PhotoFileSize; )
						{
							if(((utf[x] & MASK3BYTES) == MASK3BYTES) && ((utf[x+1] & MASKBYTE) == MASKBYTE) && ((utf[x+2] & MASKBYTE) == MASKBYTE))
							{// 1110xxxx 10xxxxxx 10xxxxxx
								PhotoBuf[y++] = ((utf[x] & 0x0F) << 12) | ((utf[x+1] & MASKBITS) << 6) | (utf[x+2] & MASKBITS);
								x += 3;
							}
							else if(((utf[x] & MASK2BYTES) == MASK2BYTES) && ((utf[x+1] & MASKBYTE) == MASKBYTE))
							{// 110xxxxx 10xxxxxx
								PhotoBuf[y++] = ((utf[x] & 0x1F) << 6) | (utf[x+1] & MASKBITS);
								x += 2;
							}
							else if(utf[x] < MASKBYTE)// 0xxxxxxx
								PhotoBuf[y++] = utf[x++];
							else
								PhotoBuf[y++] = utf[x++];//not utf-8 character

						}
						free(utf);

						PhotoFileSize = y;
						NamePtr = &Buf[Indiv[IndivNum].Name];
						for (x2 = 0; x2 < PhotoFileSize; x2++)
						{
							if ((PhotoBuf[x2] == '\n') && ((x2+1) < PhotoFileSize))
							{
								x = x2+1;//to beginning of next line
								for (y = 0; (PhotoBuf[x] != '<') && (PhotoBuf[x] != '@') && (x < PhotoFileSize); x++, y++)
									Name[y] = PhotoBuf[x];
								Name[y-1] = 0;//ignore ' ' before '>' or '@'
								if (PhotoBuf[x] == '@')
								{
									for ( ; (PhotoBuf[x] < '0') || (PhotoBuf[x] > '9'); x++)
										;
									PhotoID = Atoi(&PhotoBuf[x]);
									if (PhotoID == Indiv[IndivNum].Num)
									{
										RemovePhoto(x2+1);
										break;
									}
								}
								else if (PhotoBuf[x] == '<')
								{
									x += 3;//past "<> "
									for (z = 0; z < 30; z++)
										if (NamePtr[z] != Name[z])
											break;
									if (NamePtr[z] == '\r')
									{
										RemovePhoto(x2+1);
										break;
									}
								}
							}
						}
						free(PhotoBuf);
					}
				}
				if (hPhotoFile)
					CloseHandle(hPhotoFile);
//				SetFocus(hwndIndiv);
				SendMessage(hwndIndiv, WM_COMMAND, IDOK, 0);
			}
			break;

		case IDC_BUTTON14://Show Photo or Link Photo
//			GetPhotoFileName();
			hPhotoFile = CreateFile(SimpleFamilyTreePhotosTxt, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL);
			if (hPhotoFile != INVALID_HANDLE_VALUE)
			{
				DWORD x2 = 0;

				if (PhotoFileSize = GetFileSize(hPhotoFile, NULL))
				{
					utf = (BYTE*)malloc(PhotoFileSize);
					ReadFile(hPhotoFile, utf, PhotoFileSize, &dwBytesRead, NULL);
					PhotoBuf = (TCHAR*)malloc(sizeof(TCHAR)*PhotoFileSize);
					for (x = 0, y = 0; x < PhotoFileSize; )
					{
						if(((utf[x] & MASK3BYTES) == MASK3BYTES) && ((utf[x+1] & MASKBYTE) == MASKBYTE) && ((utf[x+2] & MASKBYTE) == MASKBYTE))
						{// 1110xxxx 10xxxxxx 10xxxxxx
							PhotoBuf[y++] = ((utf[x] & 0x0F) << 12) | ((utf[x+1] & MASKBITS) << 6) | (utf[x+2] & MASKBITS);
							x += 3;
						}
						else if(((utf[x] & MASK2BYTES) == MASK2BYTES) && ((utf[x+1] & MASKBYTE) == MASKBYTE))
						{// 110xxxxx 10xxxxxx
							PhotoBuf[y++] = ((utf[x] & 0x1F) << 6) | (utf[x+1] & MASKBITS);
							x += 2;
						}
						else if(utf[x] < MASKBYTE)// 0xxxxxxx
							PhotoBuf[y++] = (TCHAR)utf[x++];
						else
							PhotoBuf[y++] = (TCHAR)utf[x++];//not utf-8 character
					}
					free(utf);
					if (Indiv[IndivNum].Flags & 0x100000)
					{
						NamePtr = &Buf[Indiv[IndivNum].Name];
 						for ( ; x2 < PhotoFileSize; x2++)
						{
							if (PhotoBuf[x2] == '\n')
							{
								x = x2+1;//to beginning of next line
								for (y = 0; ((PhotoBuf[x] != '@') && (PhotoBuf[x] != '<')) && (x < PhotoFileSize); x++, y++)
									Name[y] = PhotoBuf[x];
								Name[y-1] = 0;//ignore ' ' before '>'
								if (PhotoBuf[x] == '@')
								{//search on IndivNum
									for ( ; (PhotoBuf[x] < '0') || (PhotoBuf[x] > '9'); x++)
										;
									PhotoID = Atoi(&PhotoBuf[x]);
									if (PhotoID == Indiv[IndivNum].Num)
									{
										for (y = x; (PhotoBuf[y] != '@') && (y < PhotoFileSize); y++)
											;
										if (y != PhotoFileSize)
										{
											y += 2;//to beginning of photot filename
											x = y;
											for ( ; (y < PhotoFileSize) && (PhotoBuf[y] != '\r'); y++)
												;
											PhotoBuf[y] = 0;
											Jpeg = &PhotoBuf[x];
											hJpegFile = CreateFile(Jpeg, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
											if (hJpegFile != INVALID_HANDLE_VALUE)
											{
												if (JpegFileSize = GetFileSize(hJpegFile, NULL))
												{
													JpegBuf = (BYTE*)malloc(JpegFileSize);
													ReadFile(hJpegFile, JpegBuf, JpegFileSize, &dwBytesRead, NULL);
													CloseHandle(hJpegFile);
													ShowJpeg();
													free(JpegBuf);
												}
												else
												{
													CloseHandle(hJpegFile);
													MessageBox(hwnd, TEXT("Jpeg file is empty."), ERROR, MB_OK);
												}
											}
											else//didn't find that jpeg file
												MessageBox(hwnd, TEXT("This individual has an invalid photo link.\nSelect Remove Photo Link."), TEXT(""), MB_OK);
											goto endofor;
										}
									}
								}
								else if (PhotoBuf[x] == '<')
								{
									x += 3;//past "<> "
									for (z = 0; z < 30; z++)
										if (NamePtr[z] != Name[z])
											break;
									if (NamePtr[z] == '\r')
									{
										for (y = x; (y < PhotoFileSize) && (PhotoBuf[y] != '\r'); y++)
											;
										PhotoBuf[y] = 0;
										Jpeg = &PhotoBuf[x];
										hJpegFile = CreateFile(Jpeg, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
										if (hJpegFile != INVALID_HANDLE_VALUE)
										{
											if (JpegFileSize = GetFileSize(hJpegFile, NULL))
											{
												JpegBuf = (BYTE*)malloc(JpegFileSize);
												ReadFile(hJpegFile, JpegBuf, JpegFileSize, &dwBytesRead, NULL);
												CloseHandle(hJpegFile);
												ShowJpeg();
												free(JpegBuf);
											}
											else
											{
												CloseHandle(hJpegFile);
												MessageBox(hwnd, TEXT("Jpeg file is empty."), ERROR, MB_OK);
											}
										}
										else//didn't find that jpeg file
											MessageBox(hwnd, TEXT("This individual has an invalid photo link.\nSelect Remove Photo Link."), TEXT(""), MB_OK);
										break;
									}
								}
							}
						}
					}
					else
						x2 = PhotoFileSize;//flag
endofor:			free(PhotoBuf);
				}
				if (x2 == PhotoFileSize)
				{//not found, so add photo link
					ofn.lpstrFilter = TEXT(" *.jpg\0*.jpg\0\0");
					ofn.lpstrFile = FullPhotoFilename;
					ofn.lpstrFileTitle = PhotoFilename;
					ofn.lpstrTitle = TEXT("Select a photo to link to");
					ofn.lpstrDefExt = TEXT("jpg");
					if (PhotoDirectory[0])
						ofn.lpstrInitialDir = PhotoDirectory;
					if (GetOpenFileName(&ofn))
					{
						x = 0;
						if (PhotoFileSize == 0)
						{
							ThisPhotoBuf[x++] = '\r';
							ThisPhotoBuf[x++] = '\n';
						}
						for (y = Indiv[IndivNum].Name, z = 0; (y < fileSize) && (Buf[y] != '\r') && (Buf[y] != '\n'); y++)
							Name[z++] = Buf[y];
						Name[z] = 0;
						for (y = 0; Name[y] != 0; x++, y++)
							ThisPhotoBuf[x] = Name[y];
						ThisPhotoBuf[x++] = ' ';
						for (y = Indiv[IndivNum].Name; (y != 0) && (Buf[y] != '@'); y--)
							;
						if (Buf[y] == '@')
						{
							z = y;
							for (y--; (y != 0) && (Buf[y] != '@') && (Buf[y] != '\r'); y--)
								;
							if (Buf[y] == '@')
								for ( ; y <= z; x++, y++)
									ThisPhotoBuf[x] = Buf[y];
						}
						else
						{
							ThisPhotoBuf[x++] = '<';
							ThisPhotoBuf[x++] = '>';
						}
						ThisPhotoBuf[x++] = ' ';
						for (y = 0; FullPhotoFilename[y] != 0; x++, y++)
							ThisPhotoBuf[x] = FullPhotoFilename[y];
						ThisPhotoBuf[x++] = '\r';
						ThisPhotoBuf[x++] = '\n';
						for (z = 0, y = 0; (z < x) && (y < 512); z++)
						{
							if (ThisPhotoBuf[z] < 0x80)
								bThisPhotoBuf[y++] = (BYTE)ThisPhotoBuf[z];
							else if (ThisPhotoBuf[z] < 0x800)
							{
								bThisPhotoBuf[y++] = ((BYTE)(MASK2BYTES | ThisPhotoBuf[z] >> 6));
								bThisPhotoBuf[y++] = ((BYTE)(MASKBYTE | ThisPhotoBuf[z] & MASKBITS));
							}
							else if(ThisPhotoBuf[z] < 0x10000)
							{
								bThisPhotoBuf[y++] = ((BYTE)(MASK3BYTES | ThisPhotoBuf[z] >> 12));
								bThisPhotoBuf[y++] = ((BYTE)(MASKBYTE | ThisPhotoBuf[z] >> 6 & MASKBITS));
								bThisPhotoBuf[y++] = ((BYTE)(MASKBYTE | ThisPhotoBuf[z] & MASKBITS));
							}
						}
						SetFilePointer(hPhotoFile, 0, NULL, FILE_END);
						WriteFile(hPhotoFile, bThisPhotoBuf, y, &dwBytesWritten, NULL);
						Indiv[IndivNum].Flags |= 0x100000;
 						SendMessage(hwndIndiv, WM_COMMAND, IDOK, 0);
					}
					else
						SetFocus(hwndIndiv);
					ofn.lpstrInitialDir = CurrentDir;
				}
			}
			if (hPhotoFile)
				CloseHandle(hPhotoFile);
			break;

		case IDC_BUTTON1:
			DialogBox(hInst, TEXT("GED"), hwndIndiv, GEDProc);
			break;

		case IDC_BUTTON2://father
			if (anyeditit)
			{
				MessageBeep(MB_OK);
				break;
			}
			x = Indiv[IndivNum].Childof & 0x7FFFFFFF;
			if (x != 0)
			{
				for (i = 0; i < LastIndiv; i++)
				{
					for (s = 0; (s < MAXSPOUSES) && (Indiv[i].Spouseof[s]); s++)
					{
						if ((x == (Indiv[i].Spouseof[s] & 0x7FFFFFFF)) && (Indiv[i].Sex == 1))
						{
							MessageBox(hwndIndiv, TEXT("already has a father.\nTo add another man as an adoptive parent,\nhighlight that man,\nthen link this individual to him as a child."), Name, MB_OK);
							goto x19;
						}
					}
				}
			}
			newfather = TRUE;
			goto x15;
		case IDC_BUTTON3://spouse
			if ((anyeditit) || (Indiv[IndivNum].Spouseof[MAXSPOUSES-1]))
			{
				MessageBeep(MB_OK);
				break;
			}
			i = 0;
			newspouse = TRUE;
			goto x15;
		case IDC_BUTTON4://child
			if (anyeditit)
			{
				MessageBeep(MB_OK);
				break;
			}
			i = 0;
			newchild = TRUE;
			goto x15;
		case IDC_BUTTON6://mother
			if (anyeditit)
			{
				MessageBeep(MB_OK);
				break;
			}
			x = Indiv[IndivNum].Childof & 0x7FFFFFFF;
			if (x != 0)
			{
				for (i = 0; i < LastIndiv; i++)
				{
					for (s = 0; (s < MAXSPOUSES) && (Indiv[i].Spouseof[s]); s++)
					{
						if ((x == (Indiv[i].Spouseof[s] & 0x7FFFFFFF)) && (Indiv[i].Sex == 0xFFFF))
						{
							MessageBox(hwndIndiv, TEXT("already has a mother.\nTo add another woman as an adoptive parent,\nhighlight that woman,\nthen link this individual to her as a child."), Name, MB_OK);
							goto x19;
						}
					}
				}
			}
			newmother = TRUE;

x15:;
			anyeditit = TRUE;
			Response = DialogBox(hInst, TEXT("NEW"), hwnd, NewProc);
			if (Response == 123)
			{//new individual
				newindiv = TRUE;
				fromnewlink = TRUE;
				Response = DialogBox(hInst, TEXT("NEWINDIVIDUAL"), hwnd, NewIndivProc);
				Sex = Sex2[6];
			}
			else if (Response == 321)
			{//link to an existing individual
				newindiv = FALSE;
				fromnewlink = TRUE;

				if (DialogBox(hInst, TEXT("LIST"), hwnd, ListProc))//trick
				{
					if ((newfather) && (Indiv[i].Sex != 1))//i comes from DialogBox
					{
						newfather = FALSE;
						for (y = Indiv[i].Name, z = 0; (y < fileSize) && (Buf[y] != '\r') && (Buf[y] != '\n'); y++)
							if (Buf[y] != '/')
								Name[z++] = Buf[y];
						Name[z] = 0;
						MessageBox(hwnd, TEXT("can't be a father (she's female)."), Name, MB_OK);
						goto x19;
					}
					else if ((newmother) && (Indiv[i].Sex != 0xFFFF))
					{
						newmother = FALSE;
						for (y = Indiv[i].Name, z = 0; (y < fileSize) && (Buf[y] != '\r') && (Buf[y] != '\n'); y++)
							if (Buf[y] != '/')
								Name[z++] = Buf[y];
						Name[z] = 0;
						ch = Buf[y];
						Buf[y] = 0;
						MessageBox(hwnd, TEXT("can't be a mother (he's male)."), Name, MB_OK);
						Buf[y] = ch;
						goto x19;
					}
					for (NewIndivOffset = Indiv[i].Name; (NewIndivOffset != 0) && ((Buf[NewIndivOffset] != '\n') || (Buf[NewIndivOffset+1] != '0')); NewIndivOffset--)
						;
					NewIndivOffset++;//NewIndivOffset is beginning of new individual's record in Buf
					Number2 = Indiv[i].Num;//the number of the individual added (IndivNum is the Indiv offset of the individual adding someone)
					if (Indiv[i].Sex == 1)
						Sex = 'M';
					else if (Indiv[i].Sex == 0xFFFF)
						Sex = 'F';
					else
						Sex = 0;
				}
				else
					goto x19;
			}

			if (Response)
			{
				for (IndivOffset = Indiv[IndivNum].Name; (IndivOffset != 0) && ((Buf[IndivOffset] != '\n') || (Buf[IndivOffset+1] != '0')); IndivOffset--)
					;
				IndivOffset++;//IndivOffset is beginning of individual's record in Buf

				if (newspouse)
				{//IndivNum is the person getting the spouse and i is the perspective spouse
					dontupdateindiv = TRUE;
					for (s = 0; (s < MAXSPOUSES) && (Indiv[IndivNum].Spouseof[s]); s++)
					{
						for (ws = 0; (ws < MAXSPOUSES) && (Indiv[i].Spouseof[ws]); ws++)
						{
							if ((Indiv[IndivNum].Spouseof[s] & 0x7FFFFFFF) == (Indiv[i].Spouseof[ws] & 0x7FFFFFFF))
							{
								MessageBox(hwnd, TEXT("Can't marry the same person more than once\n(as far as a family tree is concerned)!"), Name, MB_OK);
								goto x19;
							}
						}
					}

					if (FALSE == CheckRelative(highlighted, i))
					{
						MessageBox(hwnd, TEXT("A marriage to an ancestor/descendant\n is not allowed in this program."), ERROR, MB_OK);
						goto x19;
					}
					if (Indiv[IndivNum].Spouseof[0])
					{//if he has a spouse or child
						g = 0;
						for (s = 0; (s < MAXSPOUSES) && (Indiv[IndivNum].Spouseof[s]); s++)
						{
							for (I = 0; I < LastIndiv; I++)
							{
								if (I == IndivNum)
									continue;
								for (w = 0; (w < MAXSPOUSES) && (Indiv[I].Spouseof[w]); w++)
								{
									if ((Indiv[I].Spouseof[w] & 0x7FFFFFFF) == (Indiv[IndivNum].Spouseof[s] & 0x7FFFFFFF))
									{
										GotSpouse[g++] = Indiv[IndivNum].Spouseof[s] & 0x7FFFFFFF;
									}
								}
							}
						}
						for (s = 0; (s < MAXSPOUSES) && (Indiv[IndivNum].Spouseof[s]); s++)
						{
							for (I = 0; I < LastIndiv; I++)
							{
								if ((Indiv[I].Childof & 0x7FFFFFFF) == (Indiv[IndivNum].Spouseof[s] & 0x7FFFFFFF))
								{
									for (x = 0; x < g; x++)
										if (GotSpouse[x] == (Indiv[IndivNum].Spouseof[s] & 0x7FFFFFFF))
											break;
									if (x == g)
									{//individual has a child without having a spouse
										for (y = Indiv[IndivNum].Name, z = 0; (y < fileSize) && (Buf[y] != '\r') && (Buf[y] != '\n'); y++)
											if (Buf[y] != '/')
												Name[z++] = Buf[y];
										Name[z] = 0;
										for (y = Indiv[i].Name, z = 0; (y < fileSize) && (Buf[y] != '\r') && (Buf[y] != '\n'); y++)
											if (Buf[y] != '/')
												Name1[z++] = Buf[y];
										Name1[z] = 0;
										if (Indiv[IndivNum].Sex != Indiv[i].Sex)
										{
											_snwprintf(Error, 512, TEXT("Are the offspring of %s\nalso the offspring of %s?"), Name, Name1);
											if (IDYES == MessageBox(hwnd, Error, TEXT(""), MB_YESNO))
											{
												FamNum = Indiv[IndivNum].Spouseof[s] & 0x7FFFFFFF;
												if (Sex == 0)
													goto x17;
												if (Sex == 'M')
													PutFAM(MAN, NewIndivOffset);
												else if (Sex == 'F')
													PutFAM(WOMAN, NewIndivOffset);
												PutFAMS(NewIndivOffset);
												goto x17;
											}
										}
//										else
//											MessageBox(hwnd, SameSex, "", MB_OK);
									}
								}
							}
						}
					}
					if (Indiv[i].Spouseof[0])
					{//if prospective spouse has a spouse/child
						g = 0;
						for (s = 0; (s < MAXSPOUSES) && (Indiv[i].Spouseof[s]); s++)
						{
							for (I = 0; I < LastIndiv; I++)
							{
								if (I == i)
									continue;
								for (w = 0; (w < MAXSPOUSES) && (Indiv[I].Spouseof[w]); w++)
								{
									if ((Indiv[I].Spouseof[w] & 0x7FFFFFFF) == (Indiv[i].Spouseof[s] & 0x7FFFFFFF))
									{
										GotSpouse[g++] = Indiv[i].Spouseof[s] & 0x7FFFFFFF;
									}
								}
							}
						}
						for (s = 0; (s < MAXSPOUSES) && (Indiv[i].Spouseof[s]); s++)
						{
							for (I = 0; I < LastIndiv; I++)
							{
								if ((Indiv[I].Childof & 0x7FFFFFFF) == (Indiv[i].Spouseof[s] & 0x7FFFFFFF))
								{
									for (x = 0; x < g; x++)
										if (GotSpouse[x] == (Indiv[i].Spouseof[s] & 0x7FFFFFFF))
											break;
									if (x == g)
									{//individual has a child without having a spouse
										TCHAR tempName[256];
										for (w = 0, z = Indiv[i].Name; (z < (Indiv[i].Name+256)) && (Buf[z] != '\r') && (Buf[z] != '\n'); z++)
											if (Buf[z] != '/')
												tempName[w++] = Buf[z];
										tempName[w] = 0;
										for (w = 0, z = Indiv[IndivNum].Name; (z < (Indiv[IndivNum].Name+256)) && (Buf[z] != '\r') && (Buf[z] != '\n'); z++)
											if (Buf[z] != '/')
												Name[w++] = Buf[z];
										Name[w] = 0;
										if (Indiv[IndivNum].Sex != Indiv[i].Sex)
										{
											_snwprintf(temp, 256, TEXT("Are %s's offspring also\n %s's offspring?"), tempName, Name);
											if (IDYES == MessageBox(hwnd, temp, TEXT(""), MB_YESNO))
											{
												FamNum = Indiv[i].Spouseof[s] & 0x7FFFFFFF;
												if (Indiv[IndivNum].Sex == 0)
													goto x17;
												else if (Indiv[IndivNum].Sex == 1)
													PutFAM(MAN, IndivOffset);
												else if (Indiv[IndivNum].Sex == 0xFFFF)
													PutFAM(WOMAN, IndivOffset);
												PutFAMS(IndivOffset);
												goto x17;
											}
										}
//										else
//											MessageBox(hwnd, SameSex, "", MB_OK);
									}
								}
							}
						}
					}
					if (Sex == 0)
						goto x17;
					else if (Sex == 'M')
					{
						PutNewFAM(MAN, NewIndivOffset);
						PutFAM(WOMAN, IndivOffset);
					}
					else if (Sex == 'F')
					{
						PutNewFAM(MAN, IndivOffset);
						PutFAM(WOMAN, NewIndivOffset);
					}
					if (NewIndivOffset > IndivOffset)
					{
						PutFAMS(NewIndivOffset);
						PutFAMS(IndivOffset);
					}
					else
					{
						PutFAMS(IndivOffset);
						PutFAMS(NewIndivOffset);
					}
				}

				else if (newchild)
				{
					if (FALSE == CheckRelative(highlighted, i))//check for an attempt to make an ancestor a child
					{
						MessageBox(hwnd, TEXT("Can't make an ancestor/descendant a child!"), ERROR, MB_OK);
						goto x19;
					}
					FamNum = 0xFFFFFFFF;//flag
					for (x = IndivOffset+1; (x < fileSize) && ((Buf[x] != '\n') || (Buf[x+1] != '0')); x++)
					{
						if ((Buf[x] == '\n') && (Buf[x+1] == '1') && (Buf[x+3] == 'F') && (Buf[x+4] == 'A') && (Buf[x+5] == 'M') && (Buf[x+6] == 'S'))
						{
							FamNum = Atoi(&Buf[x+10]);
							for (x++, y = 0; Buf[x] != '\n'; x++, y++)
								Famspouse[y] = Buf[x];
							Famspouse[y++] = '\n';
							Famspouse[y] = 0;
							break;
						}
					}
					if (FamNum == 0xFFFFFFFF)//no FAMS
					{//prospective parent doesn't have a spouse/child
						CheckifChild(NewIndivOffset);//the child
						if (FamNum == 0xFFFFFFFE)
						{
							MessageBox(hwnd, TEXT("This child already has two sets of parents"),ERROR, MB_OK);
							goto x19;
						}
						if (Indiv[IndivNum].Sex == 0)
							goto x17;
						if (Indiv[IndivNum].Sex == 1)
							PutNewFAM(MAN, IndivOffset);
						else if (Indiv[IndivNum].Sex == 0xFFFF)
							PutNewFAM(WOMAN, IndivOffset);
						PutFAM(CHILD, NewIndivOffset);
						if (NewIndivOffset > IndivOffset)
						{
							PutFAMC(NewIndivOffset);
							PutFAMS(IndivOffset);
						}
						else
						{
							PutFAMS(IndivOffset);
							PutFAMC(NewIndivOffset);
						}
					}
					else
					{//ask which couple to add the child to, and add the appropriate FAMC to the child's record
						childhasparents = FALSE;
						if (CheckifChild(NewIndivOffset))
						{
							childhasparents = TRUE;
							if (FamNum == 0xFFFFFFFE)
							{
								MessageBox(hwnd, TEXT("This child already has two sets of parents."), ERROR, MB_OK);
								goto x19;
							}
						}
						GetNameinBuf(NewIndivOffset, ChildsName);//prevy comes from here
						foundspouse = FALSE;
						FamNum = 0;//flag
						SingleParentFamNum = 0;
						for (s = 0; (s < MAXSPOUSES) && (Indiv[IndivNum].Spouseof[s]); s++)
						{
							notherspouse = TRUE;
							for (I = 0; I < LastIndiv; I++)
							{
								if (I == IndivNum)
									continue;
								for (w = 0; (w < MAXSPOUSES) && (Indiv[I].Spouseof[w]); w++)
								{
									if ((Indiv[I].Spouseof[w] & 0x7FFFFFFF) == (Indiv[IndivNum].Spouseof[s] & 0x7FFFFFFF))
									{
										notherspouse = FALSE;
										foundspouse = TRUE;
										GetNameinBuf(IndivOffset, ParentsName);//prevy comes from here
										if ((childhasparents) && (prevy == 0))
											continue;//single parent can't adopt
										for (x = Indiv[I].Name; (Buf[x] != '\r') && (Buf[x] != '\n'); x++)
										{
											if (Buf[x] != '/')
												ParentsName[y++] = Buf[x];
										}
										ParentsName[y++] = '?';
										ParentsName[y] = 0;
										y = 0;
										if (Indiv[IndivNum].Sex != Indiv[I].Sex)
										{
											if (IDYES == MessageBox(hwnd, ParentsName, ChildsName, MB_YESNO))
											{
												if (Indiv[i].Childof)//or childhasparents
												{
													for (s = 0; (s < MAXSPOUSES) && (Indiv[I].Spouseof[s]); s++)
													{
														if ((Indiv[I].Spouseof[s] & 0x7FFFFFFF) == (Indiv[i].Childof & 0x7FFFFFFF))
														{//got child's parent(s)
															for (s = 0; (s < MAXSPOUSES) && (Indiv[I].Spouseof[s]); s++)
															{
																for (w = 0; (w < MAXSPOUSES) && (Indiv[IndivNum].Spouseof[w]); w++)
																{
																	if ((Indiv[I].Spouseof[s] & 0x7FFFFFFF) == (Indiv[IndivNum].Spouseof[w] & 0x7FFFFFFF))
																	{//if current parent and prospective parent are already spouses
																		MessageBox(hwnd, TEXT("Un-link the child or spouse first."), TEXT(""), MB_OK);
																		goto x19;
																	}
																}
															}
														}
													}
												}
												FamNum = Indiv[I].Spouseof[w] & 0x7FFFFFFF;
												PutFAM(CHILD, NewIndivOffset);
												PutFAMC(NewIndivOffset);
												goto x17;
											}
										}
//										else
//											MessageBox(hwnd, SameSex, "", MB_OK);
									}
								}
							}
							if (notherspouse == TRUE)
								SingleParentFamNum = Indiv[IndivNum].Spouseof[s] & 0x7FFFFFFF;
						}
						if ((foundspouse) && (childhasparents == FALSE))
						{
							for (x = 0, y = prevy; Nonelse[x] != 0; x++, y++)
								ParentsName[y] = Nonelse[x];
							ParentsName[y] = 0;
							if (IDYES == MessageBox(hwnd, ParentsName, ChildsName, MB_YESNO))
