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