1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/mimetype.cpp
3 // Purpose:     classes and functions to manage MIME types
4 // Author:      Vadim Zeitlin
5 // Modified by:
6 // Created:     23.09.98
7 // Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8 // Licence:     wxWindows licence (part of wxExtra library)
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // for compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13 
14 #ifdef __BORLANDC__
15     #pragma hdrstop
16 #endif
17 
18 #if wxUSE_MIMETYPE
19 
20 #include "wx/msw/mimetype.h"
21 
22 #ifndef WX_PRECOMP
23     #include "wx/dynarray.h"
24     #include "wx/string.h"
25     #include "wx/intl.h"
26     #include "wx/log.h"
27     #include "wx/crt.h"
28     #if wxUSE_GUI
29         #include "wx/icon.h"
30         #include "wx/msgdlg.h"
31     #endif
32 #endif //WX_PRECOMP
33 
34 #include "wx/file.h"
35 #include "wx/iconloc.h"
36 #include "wx/confbase.h"
37 
38 #ifdef __WINDOWS__
39     #include "wx/msw/registry.h"
40     #include "wx/msw/private.h"
41 #endif // OS
42 
43 // other standard headers
44 #include <ctype.h>
45 
46 // in case we're compiling in non-GUI mode
47 class WXDLLIMPEXP_FWD_CORE wxIcon;
48 
49 // These classes use Windows registry to retrieve the required information.
50 //
51 // Keys used (not all of them are documented, so it might actually stop working
52 // in future versions of Windows...):
53 //  1. "HKCR\MIME\Database\Content Type" contains subkeys for all known MIME
54 //     types, each key has a string value "Extension" which gives (dot preceded)
55 //     extension for the files of this MIME type.
56 //
57 //  2. "HKCR\.ext" contains
58 //   a) unnamed value containing the "filetype"
59 //   b) value "Content Type" containing the MIME type
60 //
61 // 3. "HKCR\filetype" contains
62 //   a) unnamed value containing the description
63 //   b) subkey "DefaultIcon" with single unnamed value giving the icon index in
64 //      an icon file
65 //   c) shell\open\command and shell\open\print subkeys containing the commands
66 //      to open/print the file (the positional parameters are introduced by %1,
67 //      %2, ... in these strings, we change them to %s ourselves)
68 
69 // Notice that HKCR can be used only when reading from the registry, when
70 // writing to it, we need to write to HKCU\Software\Classes instead as HKCR is
71 // a merged view of that location and HKLM\Software\Classes that we generally
72 // wouldn't have the write permissions to but writing to HKCR will try writing
73 // to the latter unless the key being written to already exists under the
74 // former, resulting in a "Permission denied" error without administrative
75 // permissions. So the right thing to do is to use HKCR when reading, to
76 // respect both per-user and machine-global associations, but only write under
77 // HKCU.
78 static const wxStringCharType *CLASSES_ROOT_KEY = wxS("Software\\Classes\\");
79 
80 // although I don't know of any official documentation which mentions this
81 // location, uses it, so it isn't likely to change
82 static const wxChar *MIME_DATABASE_KEY = wxT("MIME\\Database\\Content Type\\");
83 
84 // this function replaces Microsoft %1 with Unix-like %s
CanonicalizeParams(wxString & command)85 static bool CanonicalizeParams(wxString& command)
86 {
87     // transform it from '%1' to '%s' style format string (now also test for %L
88     // as apparently MS started using it as well for the same purpose)
89 
90     // NB: we don't make any attempt to verify that the string is valid, i.e.
91     //     doesn't contain %2, or second %1 or .... But we do make sure that we
92     //     return a string with _exactly_ one '%s'!
93     bool foundFilename = false;
94     size_t len = command.length();
95     for ( size_t n = 0; (n < len) && !foundFilename; n++ )
96     {
97         if ( command[n] == wxT('%') &&
98                 (n + 1 < len) &&
99                 (command[n + 1] == wxT('1') || command[n + 1] == wxT('L')) )
100         {
101             // replace it with '%s'
102             command[n + 1] = wxT('s');
103 
104             foundFilename = true;
105         }
106     }
107 
108     if ( foundFilename )
109     {
110         // Some values also contain an addition %* expansion string which is
111         // presumably supposed to be replaced with the names of the other files
112         // accepted by the command. As we don't support more than one file
113         // anyhow, simply ignore it.
114         command.Replace(" %*", "");
115     }
116 
117     return foundFilename;
118 }
119 
Init(const wxString & strFileType,const wxString & ext)120 void wxFileTypeImpl::Init(const wxString& strFileType, const wxString& ext)
121 {
122     // VZ: does it? (FIXME)
123     wxCHECK_RET( !ext.empty(), wxT("needs an extension") );
124 
125     if ( ext[0u] != wxT('.') ) {
126         m_ext = wxT('.');
127     }
128     m_ext << ext;
129 
130     m_strFileType = strFileType;
131     if ( !strFileType ) {
132         m_strFileType = m_ext.AfterFirst('.') + wxT("_auto_file");
133     }
134 }
135 
GetVerbPath(const wxString & verb) const136 wxString wxFileTypeImpl::GetVerbPath(const wxString& verb) const
137 {
138     wxString path;
139     path << m_strFileType << wxT("\\shell\\") << verb << wxT("\\command");
140     return path;
141 }
142 
GetAllCommands(wxArrayString * verbs,wxArrayString * commands,const wxFileType::MessageParameters & params) const143 size_t wxFileTypeImpl::GetAllCommands(wxArrayString *verbs,
144                                       wxArrayString *commands,
145                                       const wxFileType::MessageParameters& params) const
146 {
147     wxCHECK_MSG( !m_ext.empty(), 0, wxT("GetAllCommands() needs an extension") );
148 
149     if ( m_strFileType.empty() )
150     {
151         // get it from the registry
152         wxFileTypeImpl *self = wxConstCast(this, wxFileTypeImpl);
153         wxRegKey rkey(wxRegKey::HKCR, m_ext);
154         if ( !rkey.Exists() || !rkey.QueryValue(wxEmptyString, self->m_strFileType) )
155         {
156             wxLogDebug(wxT("Can't get the filetype for extension '%s'."),
157                        m_ext.c_str());
158 
159             return 0;
160         }
161     }
162 
163     // enum all subkeys of HKCR\filetype\shell
164     size_t count = 0;
165     wxRegKey rkey(wxRegKey::HKCR, m_strFileType  + wxT("\\shell"));
166     long dummy;
167     wxString verb;
168     bool ok = rkey.GetFirstKey(verb, dummy);
169     while ( ok )
170     {
171         wxString command = wxFileType::ExpandCommand(GetCommand(verb), params);
172 
173         // we want the open bverb to eb always the first
174 
175         if ( verb.CmpNoCase(wxT("open")) == 0 )
176         {
177             if ( verbs )
178                 verbs->Insert(verb, 0);
179             if ( commands )
180                 commands->Insert(command, 0);
181         }
182         else // anything else than "open"
183         {
184             if ( verbs )
185                 verbs->Add(verb);
186             if ( commands )
187                 commands->Add(command);
188         }
189 
190         count++;
191 
192         ok = rkey.GetNextKey(verb, dummy);
193     }
194 
195     return count;
196 }
197 
198 // ----------------------------------------------------------------------------
199 // modify the registry database
200 // ----------------------------------------------------------------------------
201 
EnsureExtKeyExists()202 bool wxFileTypeImpl::EnsureExtKeyExists()
203 {
204     wxRegKey rkey(wxRegKey::HKCU, CLASSES_ROOT_KEY + m_ext);
205     if ( !rkey.Exists() )
206     {
207         if ( !rkey.Create() || !rkey.SetValue(wxEmptyString, m_strFileType) )
208         {
209             wxLogError(_("Failed to create registry entry for '%s' files."),
210                        m_ext.c_str());
211             return false;
212         }
213     }
214 
215     return true;
216 }
217 
218 // ----------------------------------------------------------------------------
219 // get the command to use
220 // ----------------------------------------------------------------------------
221 
wxFileTypeImplGetCurVer(const wxString & progId)222 static wxString wxFileTypeImplGetCurVer(const wxString& progId)
223 {
224     wxRegKey key(wxRegKey::HKCR, progId + wxT("\\CurVer"));
225     if (key.Exists())
226     {
227         wxString value;
228         if (key.QueryValue(wxEmptyString, value))
229             return value;
230     }
231     return progId;
232 }
233 
GetCommand(const wxString & verb) const234 wxString wxFileTypeImpl::GetCommand(const wxString& verb) const
235 {
236     // suppress possible error messages
237     wxLogNull nolog;
238     wxString strKey;
239 
240     // Since Windows Vista the association used by Explorer is different from
241     // the association information stored in the traditional part of the
242     // registry. Unfortunately the new schema doesn't seem to be documented
243     // anywhere so using it involves a bit of guesswork:
244     //
245     // The information is stored under Explorer-specific key whose path is
246     // below. The interesting part is UserChoice subkey which is the only one
247     // we use so far but there is also OpenWithProgids subkey which can exist
248     // even if UserChoice doesn't. However in practice there doesn't seem to be
249     // any cases when OpenWithProgids values for the given extension are
250     // different from those found directly under HKCR\.ext, so for now we don't
251     // bother to use this, apparently the programs registering their file type
252     // associations do it in both places. We do use UserChoice because when the
253     // association is manually changed by the user it's only recorded there and
254     // so must override whatever value was created under HKCR by the setup
255     // program.
256 
257     {
258         wxRegKey explorerKey
259                  (
260                     wxRegKey::HKCU,
261                     wxT("Software\\Microsoft\\Windows\\CurrentVersion\\")
262                     wxT("Explorer\\FileExts\\") +
263                     m_ext +
264                     wxT("\\UserChoice")
265                  );
266         if ( explorerKey.Open(wxRegKey::Read) &&
267                 explorerKey.QueryValue(wxT("Progid"), strKey) )
268         {
269             strKey = wxFileTypeImplGetCurVer(strKey);
270         }
271     }
272 
273     if (!strKey && wxRegKey(wxRegKey::HKCR, m_ext + wxT("\\shell")).Exists())
274         strKey = m_ext;
275 
276     if ( !strKey && !m_strFileType.empty())
277     {
278         wxString fileType = wxFileTypeImplGetCurVer(m_strFileType);
279         if (wxRegKey(wxRegKey::HKCR, fileType + wxT("\\shell")).Exists())
280             strKey = fileType;
281     }
282 
283     if ( !strKey )
284     {
285         // no info
286         return wxEmptyString;
287     }
288 
289     strKey << wxT("\\shell\\") << verb;
290     wxRegKey key(wxRegKey::HKCR, strKey + wxT("\\command"));
291     wxString command;
292     if ( key.Open(wxRegKey::Read) ) {
293         // it's the default value of the key
294         if ( key.QueryValue(wxEmptyString, command) ) {
295             bool foundFilename = CanonicalizeParams(command);
296 
297 #if wxUSE_IPC
298             // look whether we must issue some DDE requests to the application
299             // (and not just launch it)
300             strKey += wxT("\\DDEExec");
301             wxRegKey keyDDE(wxRegKey::HKCR, strKey);
302             if ( keyDDE.Open(wxRegKey::Read) ) {
303                 wxString ddeCommand, ddeServer, ddeTopic;
304                 keyDDE.QueryValue(wxEmptyString, ddeCommand);
305 
306                 // in some cases "DDEExec" subkey exists but has no value, we
307                 // shouldn't use DDE in this case
308                 if ( !ddeCommand.empty() ) {
309                     ddeCommand.Replace(wxT("%1"), wxT("%s"));
310 
311                     wxRegKey keyServer(wxRegKey::HKCR, strKey + wxT("\\Application"));
312                     keyServer.QueryValue(wxEmptyString, ddeServer);
313                     wxRegKey keyTopic(wxRegKey::HKCR, strKey + wxT("\\Topic"));
314                     keyTopic.QueryValue(wxEmptyString, ddeTopic);
315 
316                     if (ddeTopic.empty())
317                         ddeTopic = wxT("System");
318 
319                     // HACK: we use a special feature of wxExecute which exists
320                     //       just because we need it here: it will establish DDE
321                     //       conversation with the program it just launched
322                     command.Prepend(wxT("WX_DDE#"));
323                     command << wxT('#') << ddeServer
324                             << wxT('#') << ddeTopic
325                             << wxT('#') << ddeCommand;
326                 }
327             }
328             else
329 #endif // wxUSE_IPC
330             if ( !foundFilename )
331             {
332                 // we didn't find any '%1' - the application doesn't know which
333                 // file to open (note that we only do it if there is no DDEExec
334                 // subkey)
335                 //
336                 // HACK: append the filename at the end, hope that it will do
337                 command << wxT(" %s");
338             }
339         }
340     }
341     //else: no such file type or no value, will return empty string
342 
343     return command;
344 }
345 
346 bool
GetOpenCommand(wxString * openCmd,const wxFileType::MessageParameters & params) const347 wxFileTypeImpl::GetOpenCommand(wxString *openCmd,
348                                const wxFileType::MessageParameters& params)
349                                const
350 {
351     wxString cmd = GetCommand(wxT("open"));
352 
353     // Some viewers don't define the "open" verb but do define "show" one, try
354     // to use it as a fallback.
355     if ( cmd.empty() )
356         cmd = GetCommand(wxT("show"));
357 
358     *openCmd = wxFileType::ExpandCommand(cmd, params);
359 
360     return !openCmd->empty();
361 }
362 
363 bool
GetPrintCommand(wxString * printCmd,const wxFileType::MessageParameters & params) const364 wxFileTypeImpl::GetPrintCommand(wxString *printCmd,
365                                 const wxFileType::MessageParameters& params)
366                                 const
367 {
368     wxString cmd = GetCommand(wxT("print"));
369 
370     *printCmd = wxFileType::ExpandCommand(cmd, params);
371 
372     return !printCmd->empty();
373 }
374 
375 // ----------------------------------------------------------------------------
376 // getting other stuff
377 // ----------------------------------------------------------------------------
378 
379 // TODO this function is half implemented
GetExtensions(wxArrayString & extensions)380 bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions)
381 {
382     if ( m_ext.empty() ) {
383         // the only way to get the list of extensions from the file type is to
384         // scan through all extensions in the registry - too slow...
385         return false;
386     }
387     else {
388         extensions.Empty();
389         extensions.Add(m_ext);
390 
391         // it's a lie too, we don't return _all_ extensions...
392         return true;
393     }
394 }
395 
GetMimeType(wxString * mimeType) const396 bool wxFileTypeImpl::GetMimeType(wxString *mimeType) const
397 {
398     // suppress possible error messages
399     wxLogNull nolog;
400     wxRegKey key(wxRegKey::HKCR, m_ext);
401 
402     return key.Open(wxRegKey::Read) &&
403                 key.QueryValue(wxT("Content Type"), *mimeType);
404 }
405 
GetMimeTypes(wxArrayString & mimeTypes) const406 bool wxFileTypeImpl::GetMimeTypes(wxArrayString& mimeTypes) const
407 {
408     wxString s;
409 
410     if ( !GetMimeType(&s) )
411     {
412         return false;
413     }
414 
415     mimeTypes.Clear();
416     mimeTypes.Add(s);
417     return true;
418 }
419 
420 
GetIcon(wxIconLocation * iconLoc) const421 bool wxFileTypeImpl::GetIcon(wxIconLocation *iconLoc) const
422 {
423     wxString strIconKey;
424     strIconKey << m_strFileType << wxT("\\DefaultIcon");
425 
426     // suppress possible error messages
427     wxLogNull nolog;
428     wxRegKey key(wxRegKey::HKCR, strIconKey);
429 
430     if ( key.Open(wxRegKey::Read) ) {
431         wxString strIcon;
432         // it's the default value of the key
433         if ( key.QueryValue(wxEmptyString, strIcon) ) {
434             // the format is the following: <full path to file>, <icon index>
435             // NB: icon index may be negative as well as positive and the full
436             //     path may contain the environment variables inside '%'
437             wxString strFullPath = strIcon.BeforeLast(wxT(',')),
438             strIndex = strIcon.AfterLast(wxT(','));
439 
440             // index may be omitted, in which case BeforeLast(',') is empty and
441             // AfterLast(',') is the whole string
442             if ( strFullPath.empty() ) {
443                 strFullPath = strIndex;
444                 strIndex = wxT("0");
445             }
446 
447             if ( iconLoc )
448             {
449                 iconLoc->SetFileName(wxExpandEnvVars(strFullPath));
450 
451                 iconLoc->SetIndex(wxAtoi(strIndex));
452             }
453 
454             return true;
455         }
456     }
457 
458     // no such file type or no value or incorrect icon entry
459     return false;
460 }
461 
GetDescription(wxString * desc) const462 bool wxFileTypeImpl::GetDescription(wxString *desc) const
463 {
464     // suppress possible error messages
465     wxLogNull nolog;
466     wxRegKey key(wxRegKey::HKCR, m_strFileType);
467 
468     if ( key.Open(wxRegKey::Read) ) {
469         // it's the default value of the key
470         if ( key.QueryValue(wxEmptyString, *desc) ) {
471             return true;
472         }
473     }
474 
475     return false;
476 }
477 
478 // helper function
479 wxFileType *
CreateFileType(const wxString & filetype,const wxString & ext)480 wxMimeTypesManagerImpl::CreateFileType(const wxString& filetype, const wxString& ext)
481 {
482     wxFileType *fileType = new wxFileType;
483     fileType->m_impl->Init(filetype, ext);
484     return fileType;
485 }
486 
487 // extension -> file type
488 wxFileType *
GetFileTypeFromExtension(const wxString & ext)489 wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& ext)
490 {
491     // add the leading point if necessary
492     wxString str;
493     if ( ext[0u] != wxT('.') ) {
494         str = wxT('.');
495     }
496     str << ext;
497 
498     // suppress possible error messages
499     wxLogNull nolog;
500 
501     bool knownExtension = false;
502 
503     wxString strFileType;
504     wxRegKey key(wxRegKey::HKCR, str);
505     if ( key.Open(wxRegKey::Read) ) {
506         // it's the default value of the key
507         if ( key.QueryValue(wxEmptyString, strFileType) ) {
508             // create the new wxFileType object
509             return CreateFileType(strFileType, ext);
510         }
511         else {
512             // this extension doesn't have a filetype, but it's known to the
513             // system and may be has some other useful keys (open command or
514             // content-type), so still return a file type object for it
515             knownExtension = true;
516         }
517     }
518 
519     if ( !knownExtension )
520     {
521         // unknown extension
522         return NULL;
523     }
524 
525     return CreateFileType(wxEmptyString, ext);
526 }
527 
528 // MIME type -> extension -> file type
529 wxFileType *
GetFileTypeFromMimeType(const wxString & mimeType)530 wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString& mimeType)
531 {
532     wxString strKey = MIME_DATABASE_KEY;
533     strKey << mimeType;
534 
535     // suppress possible error messages
536     wxLogNull nolog;
537 
538     wxString ext;
539     wxRegKey key(wxRegKey::HKCR, strKey);
540     if ( key.Open(wxRegKey::Read) ) {
541         if ( key.QueryValue(wxT("Extension"), ext) ) {
542             return GetFileTypeFromExtension(ext);
543         }
544     }
545 
546     // unknown MIME type
547     return NULL;
548 }
549 
EnumAllFileTypes(wxArrayString & mimetypes)550 size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxArrayString& mimetypes)
551 {
552     // enumerate all keys under MIME_DATABASE_KEY
553     wxRegKey key(wxRegKey::HKCR, MIME_DATABASE_KEY);
554 
555     wxString type;
556     long cookie;
557     bool cont = key.GetFirstKey(type, cookie);
558     while ( cont )
559     {
560         mimetypes.Add(type);
561 
562         cont = key.GetNextKey(type, cookie);
563     }
564 
565     return mimetypes.GetCount();
566 }
567 
568 // ----------------------------------------------------------------------------
569 // create a new association
570 // ----------------------------------------------------------------------------
571 
Associate(const wxFileTypeInfo & ftInfo)572 wxFileType *wxMimeTypesManagerImpl::Associate(const wxFileTypeInfo& ftInfo)
573 {
574     wxCHECK_MSG( !ftInfo.GetExtensions().empty(), NULL,
575                  wxT("Associate() needs extension") );
576 
577     bool ok;
578     size_t iExtCount = 0;
579     wxString filetype;
580     wxString extWithDot;
581 
582     wxString ext = ftInfo.GetExtensions()[iExtCount];
583 
584     wxCHECK_MSG( !ext.empty(), NULL,
585                  wxT("Associate() needs non empty extension") );
586 
587     if ( ext[0u] != wxT('.') )
588         extWithDot = wxT('.');
589     extWithDot += ext;
590 
591     // start by setting the entries under ".ext"
592     // default is filetype; content type is mimetype
593     const wxString& filetypeOrig = ftInfo.GetShortDesc();
594 
595     wxRegKey key(wxRegKey::HKCU, CLASSES_ROOT_KEY + extWithDot);
596     if ( !key.Exists() )
597     {
598         // create the mapping from the extension to the filetype
599         ok = key.Create();
600         if ( ok )
601         {
602 
603             if ( filetypeOrig.empty() )
604             {
605                 // make it up from the extension
606                 filetype << extWithDot.c_str() + 1 << wxT("_file");
607             }
608             else
609             {
610                 // just use the provided one
611                 filetype = filetypeOrig;
612             }
613 
614             key.SetValue(wxEmptyString, filetype);
615         }
616     }
617     else
618     {
619         // key already exists, maybe we want to change it ??
620         if (!filetypeOrig.empty())
621         {
622             filetype = filetypeOrig;
623             key.SetValue(wxEmptyString, filetype);
624         }
625         else
626         {
627             key.QueryValue(wxEmptyString, filetype);
628         }
629     }
630 
631     // now set a mimetypeif we have it, but ignore it if none
632     const wxString& mimetype = ftInfo.GetMimeType();
633     if ( !mimetype.empty() )
634     {
635         // set the MIME type
636         ok = key.SetValue(wxT("Content Type"), mimetype);
637 
638         if ( ok )
639         {
640             // create the MIME key
641             wxString strKey = MIME_DATABASE_KEY;
642             strKey << mimetype;
643             wxRegKey keyMIME(wxRegKey::HKCU, CLASSES_ROOT_KEY + strKey);
644             ok = keyMIME.Create();
645 
646             if ( ok )
647             {
648                 // and provide a back link to the extension
649                 keyMIME.SetValue(wxT("Extension"), extWithDot);
650             }
651         }
652     }
653 
654 
655     // now make other extensions have the same filetype
656 
657     for (iExtCount=1; iExtCount < ftInfo.GetExtensionsCount(); iExtCount++ )
658     {
659         ext = ftInfo.GetExtensions()[iExtCount];
660         if ( ext[0u] != wxT('.') )
661            extWithDot = wxT('.');
662         extWithDot += ext;
663 
664         wxRegKey key2(wxRegKey::HKCU, CLASSES_ROOT_KEY + extWithDot);
665         if ( !key2.Exists() )
666             key2.Create();
667         key2.SetValue(wxEmptyString, filetype);
668 
669         // now set any mimetypes we may have, but ignore it if none
670         const wxString& mimetype2 = ftInfo.GetMimeType();
671         if ( !mimetype2.empty() )
672         {
673             // set the MIME type
674             ok = key2.SetValue(wxT("Content Type"), mimetype2);
675 
676             if ( ok )
677             {
678                 // create the MIME key
679                 wxString strKey = MIME_DATABASE_KEY;
680                 strKey << mimetype2;
681                 wxRegKey keyMIME(wxRegKey::HKCU, CLASSES_ROOT_KEY + strKey);
682                 ok = keyMIME.Create();
683 
684                 if ( ok )
685                 {
686                     // and provide a back link to the extension
687                     keyMIME.SetValue(wxT("Extension"), extWithDot);
688                 }
689             }
690         }
691 
692     } // end of for loop; all extensions now point to .ext\Default
693 
694     // create the filetype key itself (it will be empty for now, but
695     // SetCommand(), SetDefaultIcon() &c will use it later)
696     wxRegKey keyFT(wxRegKey::HKCU, CLASSES_ROOT_KEY + filetype);
697     keyFT.Create();
698 
699     wxFileType *ft = CreateFileType(filetype, extWithDot);
700 
701     if (ft)
702     {
703         if (! ftInfo.GetOpenCommand ().empty() ) ft->SetCommand (ftInfo.GetOpenCommand (), wxT("open"  ) );
704         if (! ftInfo.GetPrintCommand().empty() ) ft->SetCommand (ftInfo.GetPrintCommand(), wxT("print" ) );
705         // chris: I don't like the ->m_impl-> here FIX this ??
706         if (! ftInfo.GetDescription ().empty() ) ft->m_impl->SetDescription (ftInfo.GetDescription ()) ;
707         if (! ftInfo.GetIconFile().empty() ) ft->SetDefaultIcon (ftInfo.GetIconFile(), ftInfo.GetIconIndex() );
708 
709     }
710 
711     return ft;
712 }
713 
SetCommand(const wxString & cmd,const wxString & verb,bool WXUNUSED (overwriteprompt))714 bool wxFileTypeImpl::SetCommand(const wxString& cmd,
715                                 const wxString& verb,
716                                 bool WXUNUSED(overwriteprompt))
717 {
718     wxCHECK_MSG( !m_ext.empty() && !verb.empty(), false,
719                  wxT("SetCommand() needs an extension and a verb") );
720 
721     if ( !EnsureExtKeyExists() )
722         return false;
723 
724     wxRegKey rkey(wxRegKey::HKCU, CLASSES_ROOT_KEY + GetVerbPath(verb));
725 
726     // TODO:
727     // 1. translate '%s' to '%1' instead of always adding it
728     // 2. create DDEExec value if needed (undo GetCommand)
729     return rkey.Create() && rkey.SetValue(wxEmptyString, cmd + wxT(" \"%1\"") );
730 }
731 
SetDefaultIcon(const wxString & cmd,int index)732 bool wxFileTypeImpl::SetDefaultIcon(const wxString& cmd, int index)
733 {
734     wxCHECK_MSG( !m_ext.empty(), false, wxT("SetDefaultIcon() needs extension") );
735     wxCHECK_MSG( !m_strFileType.empty(), false, wxT("File key not found") );
736 //    the next line fails on a SMBshare, I think because it is case mangled
737 //    wxCHECK_MSG( !wxFileExists(cmd), false, wxT("Icon file not found.") );
738 
739     if ( !EnsureExtKeyExists() )
740         return false;
741 
742     wxRegKey rkey(wxRegKey::HKCU,
743                   CLASSES_ROOT_KEY + m_strFileType + wxT("\\DefaultIcon"));
744 
745     return rkey.Create() &&
746            rkey.SetValue(wxEmptyString,
747                          wxString::Format(wxT("%s,%d"), cmd.c_str(), index));
748 }
749 
SetDescription(const wxString & desc)750 bool wxFileTypeImpl::SetDescription (const wxString& desc)
751 {
752     wxCHECK_MSG( !m_strFileType.empty(), false, wxT("File key not found") );
753     wxCHECK_MSG( !desc.empty(), false, wxT("No file description supplied") );
754 
755     if ( !EnsureExtKeyExists() )
756         return false;
757 
758     wxRegKey rkey(wxRegKey::HKCU, CLASSES_ROOT_KEY + m_strFileType );
759 
760     return rkey.Create() &&
761            rkey.SetValue(wxEmptyString, desc);
762 }
763 
764 // ----------------------------------------------------------------------------
765 // remove file association
766 // ----------------------------------------------------------------------------
767 
Unassociate()768 bool wxFileTypeImpl::Unassociate()
769 {
770     bool result = true;
771     if ( !RemoveOpenCommand() )
772         result = false;
773     if ( !RemoveDefaultIcon() )
774         result = false;
775     if ( !RemoveMimeType() )
776         result = false;
777     if ( !RemoveDescription() )
778         result = false;
779 
780     return result;
781 }
782 
RemoveOpenCommand()783 bool wxFileTypeImpl::RemoveOpenCommand()
784 {
785    return RemoveCommand(wxT("open"));
786 }
787 
RemoveCommand(const wxString & verb)788 bool wxFileTypeImpl::RemoveCommand(const wxString& verb)
789 {
790     wxCHECK_MSG( !m_ext.empty() && !verb.empty(), false,
791                  wxT("RemoveCommand() needs an extension and a verb") );
792 
793     wxRegKey rkey(wxRegKey::HKCU, CLASSES_ROOT_KEY + GetVerbPath(verb));
794 
795     // if the key already doesn't exist, it's a success
796     return !rkey.Exists() || rkey.DeleteSelf();
797 }
798 
RemoveMimeType()799 bool wxFileTypeImpl::RemoveMimeType()
800 {
801     wxCHECK_MSG( !m_ext.empty(), false, wxT("RemoveMimeType() needs extension") );
802 
803     wxRegKey rkey(wxRegKey::HKCU, CLASSES_ROOT_KEY + m_ext);
804     return !rkey.Exists() || rkey.DeleteSelf();
805 }
806 
RemoveDefaultIcon()807 bool wxFileTypeImpl::RemoveDefaultIcon()
808 {
809     wxCHECK_MSG( !m_ext.empty(), false,
810                  wxT("RemoveDefaultIcon() needs extension") );
811 
812     wxRegKey rkey (wxRegKey::HKCU,
813                    CLASSES_ROOT_KEY + m_strFileType  + wxT("\\DefaultIcon"));
814     return !rkey.Exists() || rkey.DeleteSelf();
815 }
816 
RemoveDescription()817 bool wxFileTypeImpl::RemoveDescription()
818 {
819     wxCHECK_MSG( !m_ext.empty(), false,
820                  wxT("RemoveDescription() needs extension") );
821 
822     wxRegKey rkey (wxRegKey::HKCU, CLASSES_ROOT_KEY + m_strFileType );
823     return !rkey.Exists() || rkey.DeleteSelf();
824 }
825 
826 #endif // wxUSE_MIMETYPE
827