Import .family file to 3.0?

Apr 2, 2009 at 2:46 AM
Hi,

Is there a way to import a .family (Family.Show 2.0) file into 3.0?

Whenever I try to open a .family file, the app hangs.

I've installed it from the Vertigo site and have both 2.0 and 3.0 on my machine.

Debugging in VS.NET 2008 shows the below exception.  Looks like there's an accomodation for old versions, but something's missing.

Ideas?  (I'm downloading the source now, so if I need to recompile, I can!)


System.MissingMethodException was unhandled
  Message="Method not found: 'Void Microsoft.FamilyShowLib.PeopleCollection.set_IsOldVersion(Boolean)'."
  Source="FamilyShow"
  StackTrace:
       at Microsoft.FamilyShow.MainWindow.LoadFamily(String fileName)
       at Microsoft.FamilyShow.MainWindow.WelcomeUserControl_OpenRecentFileButtonClick(Object sender, RoutedEventArgs e)
       at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
       at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
       at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
       at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
       at Microsoft.FamilyShow.Welcome.OpenRecentFile_Click(Object sender, RoutedEventArgs e)
       at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
       at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
       at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
       at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
       at System.Windows.Controls.Primitives.ButtonBase.OnClick()
       at System.Windows.Controls.Button.OnClick()
       at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
       at System.Windows.UIElement.OnMouseLeftButtonUpThunk(Object sender, MouseButtonEventArgs e)
       at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
       at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
       at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
       at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
       at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)
       at System.Windows.UIElement.CrackMouseButtonEventAndReRaiseEvent(DependencyObject sender, MouseButtonEventArgs e)
       at System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e)
       at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
       at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
       at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
       at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
       at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
       at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
       at System.Windows.Input.InputManager.ProcessStagingArea()
       at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
       at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
       at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
       at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
       at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
       at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
       at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
       at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
       at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
       at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
       at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
       at System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg)
       at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
       at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
       at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
       at System.Windows.Threading.Dispatcher.Run()
       at System.Windows.Application.RunDispatcher(Object ignore)
       at System.Windows.Application.RunInternal(Window window)
       at System.Windows.Application.Run(Window window)
       at System.Windows.Application.Run()
       at Microsoft.FamilyShow.App.Main()
  InnerException:
Developer
Apr 3, 2009 at 2:57 AM
Hmm, I didn't have any trouble.  I just tried with the sample windsor.family file included with the Family.Show 3.0 release and it opened fine.  There should be full support for opening and converting the old format to the new format in version 3.0

Try compiling the latest source code and running the .exe in the bin/debug folder.  It's very peculiar, possible the two versions you have installed are conflicting.

elyoh
Apr 5, 2009 at 1:18 AM
elyoh,

Thanks for the reply.

I can open the file, but it defaults to no user ("Current Person").

I ran a debug build from VS.NET and it seeems to be having an issue with looping over a Person collection (spouses) while trying to AddSpousesNodes, 272 in DiagramLogic.cs, stating that the value of the person can't be null.  This is, of course, with my .family file, not the Windsors.  Saving the file w/o selecting an individual throws a NullRef exception in People.cs's Save method, since said Current Person is null.

Ideas?

H
Developer
Apr 5, 2009 at 3:17 PM
Edited Nov 13, 2009 at 5:12 PM

I've just realised the parallels to another post (Issue#7225) by someone else stating a problem with null values.  I can't reproduce personally and was able to convert his file fine, more around people and save to the new format.  I'm using Vista,  but I also tried in XP virtual machine and that worked fine though.




Apr 9, 2009 at 10:47 AM
The problem of loading Windsor.Family into V3 must be related to XP because the special folder 

Environment

 

.SpecialFolder.MyDocuments

 

points to c:\Document and Settings....   and you later strip the spaces out of that in LoadVersion2 line 265:

photoFile = photoFile.Replace(

" ", "");

So I guess this causes the whole thing to fail as files can't be copied there.  I tried opening Windsor and converting but because there is no current person it won't convert either.  Can you please send me a copy of Windsor.Familyx ?

Brilliant application by the way!!

 

Apr 9, 2009 at 10:56 AM
Actually the above might not be the cause (though it is a problem). But already in LoadVersion2 as soon as the people are loaded, there is a spouse count and children count for Edward Wettin but the contents are null, which then causes the crash later.
Any idea why the collections are not loading correctly?  Or maybe I'm not understanding it correctly.  Sending me a Windsor.Familx would cure it :-)
Apr 9, 2009 at 11:10 AM
Edited Apr 9, 2009 at 11:13 AM
OK, I conmmented out the lines in LoadVersion2 that remove spaces from the photos and story files and Windsor  loaded just fine. But of course when I save as V3 I lose the photos and stories...
Developer
Apr 9, 2009 at 10:55 PM
Edited Apr 9, 2009 at 11:01 PM
You'll have to open an issue thread so I can upload a converted copy of the Windsor.familyx file, discussions don't have uploads.

 photoFile  is just the file name part of the path string not the part including documents and settings so I'm not sure why that would cause problems.  Spaces in file names themselves do cause problems and there is a serious bug in version 3 to do with that but it never prevented me from opening files, just notes and pictures were missing.


Developer
Apr 9, 2009 at 11:52 PM
Edited Nov 13, 2009 at 5:11 PM

The reason it's failing is because the LoadVersion2() method is not creating the files at the following location under XP.

C:\Documents and Settings\User\Local Settings\Application Data\Family.Show\

There is a problem with that path for whatever reason.  Now to work out what's wrong with that path!

Developer
Apr 10, 2009 at 12:24 AM
Edited Apr 10, 2009 at 12:26 AM
This is the problem!

  string photoFile = Path.Combine(photoFolder, Path.GetFileName(photo.FullyQualifiedPath));

// Remove spaces since they'll be packaged as %20, breaking relative paths that expect spaces
 photoFile = photoFile.Replace(" ", "");
 photo.RelativePath = photo.RelativePath.Replace(" ", "");

File.Copy(photoOldPath, photoFile, true);

photoFile  Is the full path and similarly for stories - I was wrong before.  Simple to fix.  One should remove encoded characters from Path.GetFileName(photo.FullyQualifiedPath) not photoFile.

That will then fix the problem.  It doesn't manifest in vista since the vista equivilent of C:\Documents and Settings\User\Local Settings\Application Data\Family.Show\ has no spaces!


Proposed fix:

Replace lines 256 - ~294 in People.cs with:

                       // store the stories into temp directory to be packaged into OPC later
                        foreach (Photo photo in p.Photos)
                        {
                            string photoOldPath = Path.Combine(Path.Combine(
                                Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
                                App.ApplicationFolderName), photo.RelativePath);
                                if (File.Exists(photoOldPath))
                            {

                                string photoFileName = Path.GetFileName(photo.FullyQualifiedPath);
                                //only remove spaces from the filename not the whole path
                                photoFileName = ReplaceEncodedCharacters(photoFileName);
                                photo.RelativePath = ReplaceEncodedCharacters(photo.RelativePath);

                                string photoFile = Path.Combine(photoFolder, photoFileName);

                                File.Copy(photoOldPath, photoFile, true);
                            }
                        }

                        // store the person's story into temp directory to be packaged into OPC later
                        if (p.Story != null)
                        {
                            string storyOldPath = Path.Combine(Path.Combine(
                                Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
                                App.ApplicationFolderName), p.Story.RelativePath);
                            if (File.Exists(storyOldPath))
                            {

                                string storyFileName = Path.GetFileName(p.Story.AbsolutePath);
                                //only remove spaces from the filename not the whole path
                                storyFileName = ReplaceEncodedCharacters(storyFileName);
                                p.Story.RelativePath = ReplaceEncodedCharacters(p.Story.RelativePath);

                                string storyFile = Path.Combine(storyFolder, storyFileName);

                                File.Copy(storyOldPath, storyFile, true);
                            }
                        }






Nov 26, 2009 at 8:47 AM

elyoh,

Your photo path fix above definitely gets me to import my v2 .family file, but it looks like when I select a user (any user), I'm running into what appears to be a data issue with my v2 file:

AddSpouseNodes in DiagramLogic.cs is iterating over the list of spouses and my data appears to have a null spouse in there and that's throwing an error.

It seems that whatever's in my v2 file (which works great in v2, btw), is not showing spouses or children, etc.

I'm a bit stumped, but I'm back to looking at this for a while.

Developer
Dec 1, 2009 at 12:48 AM

Here's an update to this thread based on some testing of the above proposed fix.  The above fix will sometimes fail if photo collections cannot be sucessfully created either due to missing files or duplicate entries in photo collections. If the photos do not import correctly, the whole load process is compromised which can lead to the debug information suggesting problems in DiagramLogic.cs.  Hope that helps.


Proposed fix:

        /// <summary>
        /// Load the list of people from Family.Show version 2.0 file format
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        public void LoadVersion2()
        
        {
            // Loading, clear existing nodes
            this.PeopleCollection.Clear();

            try
            {
                // Use the default path and filename if none were provided
                if (string.IsNullOrEmpty(this.FullyQualifiedFilename))
                    this.FullyQualifiedFilename = People.DefaultFullyQualifiedFilename;

                XmlSerializer xml = new XmlSerializer(typeof(People));
                using (Stream stream = new FileStream(this.FullyQualifiedFilename, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    People pc = (People)xml.Deserialize(stream);
                    stream.Close();

                    foreach (Person person in pc.PeopleCollection)
                        this.PeopleCollection.Add(person);

                    // Setup temp folders for this family to be packaged into OPC later
                    string tempFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), App.ApplicationFolderName);
                    tempFolder = Path.Combine(tempFolder, App.AppDataFolderName);
                    RecreateDirectory(tempFolder);

                    string photoFolder = Path.Combine(tempFolder, Photo.Const.PhotosFolderName);
                    RecreateDirectory(photoFolder);

                    string storyFolder = Path.Combine(tempFolder, Story.Const.StoriesFolderName);
                    RecreateDirectory(storyFolder);

                    foreach (Person p in this.PeopleCollection)
                    {
                        // To avoid circular references when serializing family data to xml, only the person Id
                        // is seralized to express relationships. When family data is loaded, the correct
                        // person object is found using the person Id and assigned to the appropriate relationship.
                        foreach (Relationship r in p.Relationships)
                        {
                            r.RelationTo = this.PeopleCollection.Find(r.PersonId);
                        }

						// Store the photos which are present on the users computer
                        PhotoCollection newPhotos = new PhotoCollection();

                        // Store the photos into temp directory to be packaged into OPC later
                        foreach (Photo photo in p.Photos)
                        {
                            string photoOldPath = Path.Combine(Path.Combine(
                                Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
                                App.ApplicationFolderName), photo.RelativePath);

                            if (File.Exists(photoOldPath) && IsPhotoFileSupported(photoOldPath))
                            {

                                string photoFileName = Path.GetFileName(photo.FullyQualifiedPath);
                                // Remove spaces from the filename.
                                photoFileName = ReplaceEncodedCharacters(photoFileName);
                                photo.RelativePath = ReplaceEncodedCharacters(photo.RelativePath);

                                string photoFile = Path.Combine(photoFolder, photoFileName);

                                File.Copy(photoOldPath, photoFile, true);

                                newPhotos.Add(photo);
                            }

                        }
						
						// Clear the old Photo collection
                        p.Photos.Clear();

						// Recreate the Collection
                        foreach (Photo newPhoto in newPhotos)
                        {
                            p.Photos.Add(newPhoto);
                        }

                        // Store the person's story into temp directory to be packaged into OPC later
                        if (p.Story != null)
                        {
                            if (p.Story.RelativePath != null)
                            {
                                string storyOldPath = Path.Combine(Path.Combine(
                                    Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
                                    App.ApplicationFolderName), p.Story.RelativePath);
                                if (File.Exists(storyOldPath))
                                {

                                    string storyFileName = Path.GetFileName(p.Story.AbsolutePath);
                                    // Remove spaces from the filename.
                                    storyFileName = ReplaceEncodedCharacters(storyFileName);
                                    p.Story.RelativePath = ReplaceEncodedCharacters(p.Story.RelativePath);

                                    string storyFile = Path.Combine(storyFolder, storyFileName);

                                    File.Copy(storyOldPath, storyFile, true);

                                }
                                else
                                {
                                    p.Story.Delete();
                                }
                            }
                        }
                    }

                    // Set the current person in the list
                    this.CurrentPersonId = pc.CurrentPersonId;
                    this.CurrentPersonName = pc.CurrentPersonName;
                    this.PeopleCollection.Current = this.PeopleCollection.Find(this.CurrentPersonId);
                    this.PeopleCollection.IsDirty = false;

                }

                this.PeopleCollection.IsDirty = false;
            }
            catch
            {
                // Could not load the file. Handle all exceptions
                // the same, ignore and continue.
                this.fullyQualifiedFilename = string.Empty;
                // Warn user of problem with file.
            }
        }

        /// <summary>
        /// Determines if an image file is supported based on its extension.
        /// </summary>
        internal static bool IsPhotoFileSupported(string fileName)
        {
            string extension = System.IO.Path.GetExtension(fileName);

            if (string.Compare(extension, ".jpg", true, System.Globalization.CultureInfo.InvariantCulture) == 0 ||
                string.Compare(extension, ".jpeg", true, System.Globalization.CultureInfo.InvariantCulture) == 0 ||
                string.Compare(extension, ".png", true, System.Globalization.CultureInfo.InvariantCulture) == 0 ||
                string.Compare(extension, ".gif", true, System.Globalization.CultureInfo.InvariantCulture) == 0)
                return true;

            return false;
        }

        /// <summary>
        /// Replaces encoded characters in file names which break relative paths.
        /// </summary>
        private static string ReplaceEncodedCharacters(string fileName)
        {
            fileName = fileName.Replace(" ", "");
            fileName = fileName.Replace("{", "");
            fileName = fileName.Replace("}", "");
            return fileName;
        }