1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is OS/2 Remote Workplace Server interface.
17 * The Initial Developer of the Original Code is
19 * Portions created by the Initial Developer are Copyright (C) 2005
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 //------------------------------------------------------------------------
41 #include "nsIGenericFactory.h"
42 #include "nsIObserver.h"
43 #include "nsIObserverService.h"
44 #include "nsDirectoryServiceDefs.h"
45 #include "nsLiteralString.h"
46 #include "nsReadableUtils.h"
47 #include "nsIStringBundle.h"
48 #include "mozilla/Services.h"
54 // nsRwsService must be included _after_ os2.h
55 #include "nsRwsService.h"
62 //------------------------------------------------------------------------
64 //------------------------------------------------------------------------
70 // use this to force debug msgs in non-debug builds
76 #define ERRMSG(x,y) { printf(y " failed - rc= %d\n", (int)x); }
78 #define ERRBREAK(x,y) if (x) { ERRMSG(x,y); break; }
80 #define ERRPRINTF(x,y) { printf(y "\n", x); }
84 #define ERRBREAK(x,y) if (x) break;
86 #define ERRPRINTF(x,y) ;
89 //------------------------------------------------------------------------
90 // function prototypes
91 //------------------------------------------------------------------------
93 static nsresult
IsDescendedFrom(PRUint32 wpsFilePtr
, const char *pszClassname
);
94 static nsresult
CreateFileForExtension(const char *aFileExt
, nsACString
& aPath
);
95 static nsresult
DeleteFileForExtension(const char *aPath
);
96 static void AssignNLSString(const PRUnichar
*aKey
, nsAString
& _retval
);
97 static nsresult
AssignTitleString(const char *aTitle
, nsAString
& result
);
99 //------------------------------------------------------------------------
100 // module-level variables - not declared as members of nsRws
101 //------------------------------------------------------------------------
103 static nsRwsService
*sRwsInstance
= 0; // our singleton instance
104 static PRBool sInit
= FALSE
; // have we tried to load RWS
106 // RWS administrative functions
107 static ULONG (* _System sRwsClientInit
)(BOOL
);
108 static ULONG (* _System sRwsGetTimeout
)(PULONG
, PULONG
);
109 static ULONG (* _System sRwsSetTimeout
)(ULONG
);
110 static ULONG (* _System sRwsClientTerminate
)(void);
112 // RWS task-oriented functions
113 static ULONG (* _System sRwsCall
)(PRWSHDR
*, ULONG
, ULONG
, ULONG
, ULONG
, ULONG
, ...);
114 static ULONG (* _System sRwsCallIndirect
)(PRWSBLD
);
115 static ULONG (* _System sRwsFreeMem
)(PRWSHDR
);
116 static ULONG (* _System sRwsGetResult
)(PRWSHDR
, ULONG
, PULONG
);
117 static ULONG (* _System sRwsGetArgPtr
)(PRWSHDR
, ULONG
, PRWSDSC
*);
119 //------------------------------------------------------------------------
120 // ExtCache - caches the default icons & handlers for file extensions
121 //------------------------------------------------------------------------
123 typedef struct _ExtInfo
133 #define kMutexTimeout 500
141 nsresult
GetIcon(const char *aExt
, PRBool aNeedMini
, PRUint32
*oIcon
);
142 nsresult
SetIcon(const char *aExt
, PRBool aIsMini
, PRUint32 aIcon
);
143 nsresult
GetHandler(const char *aExt
, PRUint32
*oHandle
, nsAString
& oTitle
);
144 nsresult
SetHandler(const char *aExt
, PRUint32 aHandle
, nsAString
& aTitle
);
148 ExtInfo
*FindExtension(const char *aExt
, PRBool aSet
= PR_FALSE
);
157 //------------------------------------------------------------------------
158 // nsIRwsService implementation
159 //------------------------------------------------------------------------
161 NS_IMPL_ISUPPORTS2(nsRwsService
, nsIRwsService
, nsIObserver
)
163 nsRwsService::nsRwsService()
165 mExtCache
= new ExtCache();
167 ERRPRINTF("", "nsRwsService - unable to allocate mExtArray%s");
170 nsRwsService::~nsRwsService()
174 //------------------------------------------------------------------------
176 // provides the default icon associated with a given extension; if the
177 // icon isn't in the cache, it creates a temp file with that extension,
178 // retrieves its icon, deletes the temp file, then caches the icon
181 nsRwsService::IconFromExtension(const char *aExt
, PRBool aNeedMini
,
184 if (!aExt
|| !*aExt
|| !_retval
)
185 return NS_ERROR_INVALID_ARG
;
187 nsresult rv
= mExtCache
->GetIcon(aExt
, aNeedMini
, _retval
);
188 if (NS_SUCCEEDED(rv
))
192 rv
= CreateFileForExtension(aExt
, path
);
193 if (NS_SUCCEEDED(rv
)) {
194 rv
= IconFromPath(path
.get(), PR_FALSE
, aNeedMini
, _retval
);
195 DeleteFileForExtension(path
.get());
196 if (NS_SUCCEEDED(rv
))
197 mExtCache
->SetIcon(aExt
, aNeedMini
, *_retval
);
203 //------------------------------------------------------------------------
205 // retrieves an object's icon using its fully-qualified path; aAbstract
206 // indicates whether this is a Filesystem object or an Abstract or
207 // Transient object; locating non-file objects is fairly expensive
210 nsRwsService::IconFromPath(const char *aPath
, PRBool aAbstract
,
211 PRBool aNeedMini
, PRUint32
*_retval
)
213 if (!aPath
|| !*aPath
|| !_retval
)
214 return NS_ERROR_INVALID_ARG
;
219 rwsType
= (aNeedMini
? RWSC_OFTITLE_OMINI
: RWSC_OFTITLE_OICON
);
221 rwsType
= (aNeedMini
? RWSC_OPATH_OMINI
: RWSC_OPATH_OICON
);
223 return RwsConvert(rwsType
, (PRUint32
)aPath
, _retval
);
226 //------------------------------------------------------------------------
228 // retrieve's an object's icon using its persistent handle
231 nsRwsService::IconFromHandle(PRUint32 aHandle
, PRBool aNeedMini
,
234 if (!aHandle
|| !_retval
)
235 return NS_ERROR_INVALID_ARG
;
237 return RwsConvert( (aNeedMini
? RWSC_OHNDL_OMINI
: RWSC_OHNDL_OICON
),
241 //------------------------------------------------------------------------
243 // retrieve's an object's title using its persistent handle
246 nsRwsService::TitleFromHandle(PRUint32 aHandle
, nsAString
& _retval
)
249 return NS_ERROR_INVALID_ARG
;
251 return RwsConvert(RWSC_OHNDL_OTITLE
, aHandle
, _retval
);
254 //------------------------------------------------------------------------
256 // provides the default handler associated with a given extension; if the
257 // info isn't in the cache, it creates a temp file with that extension,
258 // retrieves the handler's title & possibly its object handle, deletes the
259 // temp file, then caches the info.
262 nsRwsService::HandlerFromExtension(const char *aExt
, PRUint32
*aHandle
,
265 if (!aExt
|| !*aExt
|| !aHandle
)
266 return NS_ERROR_INVALID_ARG
;
268 nsresult rv
= mExtCache
->GetHandler(aExt
, aHandle
, _retval
);
269 if (NS_SUCCEEDED(rv
))
273 rv
= CreateFileForExtension(aExt
, path
);
274 if (NS_SUCCEEDED(rv
)) {
275 rv
= HandlerFromPath(path
.get(), aHandle
, _retval
);
276 DeleteFileForExtension(path
.get());
277 if (NS_SUCCEEDED(rv
))
278 mExtCache
->SetHandler(aExt
, *aHandle
, _retval
);
284 //------------------------------------------------------------------------
286 // identifies the default WPS handler for a given file; if the handler
287 // is an associated program, returns its title & object handle; if the
288 // handler is an integrated class viewer or player, it constructs a title
289 // and sets the object handle to zero
292 nsRwsService::HandlerFromPath(const char *aPath
, PRUint32
*aHandle
,
295 if (!aPath
|| !*aPath
|| !aHandle
)
296 return NS_ERROR_INVALID_ARG
;
298 nsresult rv
= NS_ERROR_FAILURE
;
305 // this dummy do{...}while(0) loop lets us bail out early
306 // while ensuring pHdr gets freed
308 // get the default view for this file
310 RWSP_MNAM
, (ULONG
)"wpQueryDefaultView",
312 RWSI_OPATH
, 0, (ULONG
)aPath
);
313 ERRBREAK(rc
, "wpQueryDefaultView")
315 PRUint32 defView
= sRwsGetResult(pHdr
, 0, 0);
316 if (defView
== (PRUint32
)-1)
319 // if the default view is OPEN_SETTINGS ('2'),
320 // change it to OPEN_RUNNING ('4')
324 // to improve efficiency, retrieve & reuse the file's wpObject
325 // ptr rather than repeatedly converting the name to an object
326 PRUint32 wpsFilePtr
= sRwsGetResult(pHdr
, 1, 0);
328 // free pHdr before the next call
332 // for default view values less than OPEN_USER, see if there
333 // is a program or program object associated with this file
334 if (defView
< 0x6500) {
336 RWSP_MNAM
, (ULONG
)"wpQueryAssociatedProgram",
338 RWSI_ASIS
, 0, wpsFilePtr
,
339 RWSI_ASIS
, 0, defView
,
343 RWSI_ASIS
, 0, (ULONG
)-1);
345 // if there's no associated program, create dummy values
346 // (if chosen, the WPS will open the file's Properties notebook)
348 if (rc
== RWSSRV_FUNCTIONFAILED
) {
350 AssignNLSString(NS_LITERAL_STRING("wpsDefaultOS2").get(), _retval
);
354 ERRMSG(rc
, "wpQueryAssociatedProgram")
358 // get a ptr to the return value's data structure; then get
359 // both the object handle we requested & the raw WPS object ptr
361 rc
= sRwsGetArgPtr(pHdr
, 0, &pRtn
);
362 ERRBREAK(rc
, "GetArgPtr")
363 *aHandle
= *((PRUint32
*)pRtn
->pget
);
364 PRUint32 wpsPgmPtr
= pRtn
->value
;
366 // free pHdr before the next call
370 // convert the object to its title (using Rws' conversion
371 // feature is more efficient than calling wpQueryTitle)
375 RWSC_OBJ_OTITLE
, 0, wpsPgmPtr
);
376 ERRBREAK(rc
, "convert pgm object to title")
378 // retrieve the title, massage it & assign to _retval, then exit
379 // N.B. no need to free pHdr here, it will be freed below
380 char *pszTitle
= (char*)sRwsGetResult(pHdr
, 1, 0);
381 if (pszTitle
!= (char*)-1)
382 rv
= AssignTitleString(pszTitle
, _retval
);
387 // the default view is provided by the file's WPS class;
388 // in this case, *aHandle is 0
390 // see if it's a known view that can be given a meaningful name
393 rv
= IsDescendedFrom(wpsFilePtr
, "MMImage");
394 if (NS_SUCCEEDED(rv
))
395 AssignNLSString(NS_LITERAL_STRING("mmImageViewerOS2").get(), _retval
);
399 case 0xbc0d: // Audio editor
400 case 0xbc21: // Video editor
401 case 0xbc17: // Midi editor
403 case 0xbbe5: { // Player
404 rv
= IsDescendedFrom(wpsFilePtr
, "MMAudio");
405 if (NS_SUCCEEDED(rv
)) {
406 AssignNLSString(NS_LITERAL_STRING("mmAudioPlayerOS2").get(), _retval
);
410 rv
= IsDescendedFrom(wpsFilePtr
, "MMVideo");
411 if (NS_SUCCEEDED(rv
)) {
412 AssignNLSString(NS_LITERAL_STRING("mmVideoPlayerOS2").get(), _retval
);
416 rv
= IsDescendedFrom(wpsFilePtr
, "MMMIDI");
417 if (NS_SUCCEEDED(rv
))
418 AssignNLSString(NS_LITERAL_STRING("mmMidiPlayerOS2").get(), _retval
);
424 rv
= IsDescendedFrom(wpsFilePtr
, "TSArcMgr");
425 if (NS_SUCCEEDED(rv
))
426 AssignNLSString(NS_LITERAL_STRING("odZipFolderOS2").get(), _retval
);
430 // this has to go last because TSEnhDataFile replaces
431 // WPDataFile; if present, all data files are descended from it
434 rv
= IsDescendedFrom(wpsFilePtr
, "TSEnhDataFile");
435 if (NS_SUCCEEDED(rv
))
436 AssignNLSString(NS_LITERAL_STRING("odTextViewOS2").get(), _retval
);
441 if (NS_SUCCEEDED(rv
))
444 // the name of this view is unknown, so create a generic name
445 // (i.e. "Viewer for Class WPSomething")
447 // use the file's object ptr to get the name of its class
451 RWSC_OBJ_CNAME
, 0, wpsFilePtr
);
452 ERRBREAK(rc
, "convert object to classname")
454 char *pszTitle
= (char*)sRwsGetResult(pHdr
, 1, 0);
455 if (pszTitle
== (char*)-1)
458 nsAutoChar16Buffer buffer
;
460 rv
= MultiByteToWideChar(0, pszTitle
, strlen(pszTitle
),
465 nsAutoString classViewer
;
466 AssignNLSString(NS_LITERAL_STRING("classViewerOS2").get(), classViewer
);
468 if ((pos
= classViewer
.Find("%S")) > -1)
469 classViewer
.Replace(pos
, 2, buffer
.Elements());
470 _retval
.Assign(classViewer
);
474 // free the pHdr allocated by the final call
479 //------------------------------------------------------------------------
481 // retrieves an object's menu using its fully-qualified path; aAbstract
482 // indicates whether this is a Filesystem object or an Abstract or
483 // Transient object; locating non-file objects is fairly expensive
486 nsRwsService::MenuFromPath(const char *aPath
, PRBool aAbstract
)
488 if (!aPath
|| !*aPath
)
489 return NS_ERROR_INVALID_ARG
;
491 nsresult rv
= NS_ERROR_FAILURE
;
493 PRUint32 type
= (aAbstract
? RWSI_OFTITLE
: RWSI_OPATH
);
498 // try to identify the window where the click occurred
499 if (WinQueryMsgPos(0, &ptl
)) {
500 hTgt
= WinQueryFocus(HWND_DESKTOP
);
502 WinMapWindowPoints(HWND_DESKTOP
, hTgt
, &ptl
, 1);
505 // if we have the window & coordinates, use them; otherwise,
506 // let RWS position the menu at the current pointer position
507 // (specifying the window ensures the focus will return to it)
510 RWSP_CMD
, RWSCMD_POPUPMENU
,
512 type
, 0, (ULONG
)aPath
,
514 RWSI_PBUF
, sizeof(POINTL
), (ULONG
)&ptl
);
517 RWSP_CMD
, RWSCMD_POPUPMENU
,
519 type
, 0, (ULONG
)aPath
,
524 ERRMSG(rc
, "RWSCMD_POPUPMENU")
533 //------------------------------------------------------------------------
535 // causes the WPS to open a file using the program specified by AppPath;
536 // this is identical to dropping the file on the program's WPS icon
539 nsRwsService::OpenWithAppHandle(const char *aFilePath
, PRUint32 aAppHandle
)
541 if (!aFilePath
|| !*aFilePath
|| !aAppHandle
)
542 return NS_ERROR_INVALID_ARG
;
544 nsresult rv
= NS_ERROR_FAILURE
;
549 RWSP_CMD
, RWSCMD_OPENUSING
,
551 RWSI_OPATH
, 0, aFilePath
,
552 RWSI_OHNDL
, 0, aAppHandle
);
554 ERRMSG(rc
, "RWSCMD_OPENUSING")
562 //------------------------------------------------------------------------
564 // causes the WPS to open a file using the program specified by AppPath;
565 // this is identical to dropping the file on the program's WPS icon
568 nsRwsService::OpenWithAppPath(const char *aFilePath
, const char *aAppPath
)
570 if (!aFilePath
|| !*aFilePath
|| !aAppPath
|| !*aAppPath
)
571 return NS_ERROR_INVALID_ARG
;
573 nsresult rv
= NS_ERROR_FAILURE
;
578 RWSP_CMD
, RWSCMD_OPENUSING
,
580 RWSI_OPATH
, 0, aFilePath
,
581 RWSI_OPATH
, 0, aAppPath
);
583 ERRMSG(rc
, "RWSCMD_OPENUSING")
591 //------------------------------------------------------------------------
592 // nsRwsService additional methods
593 //------------------------------------------------------------------------
595 // uses RwsConvert to retrieve a result that can be handled as a ULONG;
596 // type identifies the conversion, value can be anything (ULONG, char*, etc)
600 nsRwsService::RwsConvert(PRUint32 type
, PRUint32 value
, PRUint32
*result
)
602 nsresult rv
= NS_ERROR_FAILURE
;
606 PRUint32 rc
= sRwsCall(&pHdr
,
612 ERRMSG(rc
, "RwsConvert to ULONG")
614 *result
= sRwsGetResult(pHdr
, 1, 0);
615 if (*result
== (PRUint32
)-1)
625 //------------------------------------------------------------------------
627 // uses RwsConvert to retrieve a result that can be handled as a
628 // Unicode string; type identifies the conversion, value can be
629 // anything (ULONG, char*, etc)
633 nsRwsService::RwsConvert(PRUint32 type
, PRUint32 value
, nsAString
& result
)
635 nsresult rv
= NS_ERROR_FAILURE
;
639 PRUint32 rc
= sRwsCall(&pHdr
,
645 ERRMSG(rc
, "RwsConvert to string")
647 char *string
= (char*)sRwsGetResult(pHdr
, 1, 0);
648 if (string
!= (char*)-1)
649 rv
= AssignTitleString(string
, result
);
656 //------------------------------------------------------------------------
657 // nsIObserver implementation
658 //------------------------------------------------------------------------
660 // when the app shuts down, advise RwsClient; if this is the
661 // last app using RwsServer, the WPS will unload the class's dll;
662 // also, empty the extension cache to unlock & delete its icons
665 nsRwsService::Observe(nsISupports
*aSubject
, const char *aTopic
,
666 const PRUnichar
*aSomeData
)
668 if (strcmp(aTopic
, "quit-application") == 0) {
669 PRUint32 rc
= sRwsClientTerminate();
671 ERRMSG(rc
, "RwsClientTerminate");
674 mExtCache
->EmptyCache();
680 //------------------------------------------------------------------------
681 // nsRwsService static helper functions
682 //------------------------------------------------------------------------
684 // this wrapper for somIsA() makes HandlerFromPath() easier to read
686 static nsresult
IsDescendedFrom(PRUint32 wpsFilePtr
, const char *pszClassname
)
689 nsresult rv
= NS_ERROR_FAILURE
;
691 PRUint32 rc
= sRwsCall(&pHdr
,
692 RWSP_MNAMI
, (ULONG
)"somIsA",
694 RWSI_ASIS
, 0, wpsFilePtr
,
695 RWSI_CNAME
, 0, pszClassname
);
700 if (sRwsGetResult(pHdr
, 0, 0) == TRUE
)
707 //------------------------------------------------------------------------
709 // create a temp file with the specified extension, then return its path
711 static nsresult
CreateFileForExtension(const char *aFileExt
,
714 nsresult rv
= NS_ERROR_FAILURE
;
717 nsCOMPtr
<nsIFile
> tempFile
;
718 rv
= NS_GetSpecialDirectory(NS_OS_TEMP_DIR
, getter_AddRefs(tempFile
));
722 nsCAutoString
pathStr(NS_LITERAL_CSTRING("nsrws."));
723 if (*aFileExt
== '.')
725 pathStr
.Append(aFileExt
);
727 rv
= tempFile
->AppendNative(pathStr
);
731 tempFile
->GetNativePath(pathStr
);
733 FILE *fp
= fopen(pathStr
.get(), "wb+");
736 aPath
.Assign(pathStr
);
743 //------------------------------------------------------------------------
745 // delete a temp file created earlier
747 static nsresult
DeleteFileForExtension(const char *aPath
)
749 if (!aPath
|| !*aPath
)
750 return NS_ERROR_INVALID_ARG
;
756 //------------------------------------------------------------------------
758 // returns a localized string from unknownContentType.properties;
759 // if there's a failure, returns "WPS Default"
761 static void AssignNLSString(const PRUnichar
*aKey
, nsAString
& result
)
767 nsCOMPtr
<nsIStringBundleService
> bundleSvc
=
768 mozilla::services::GetStringBundleService();
772 nsCOMPtr
<nsIStringBundle
> bundle
;
773 rv
= bundleSvc
->CreateBundle(
774 "chrome://mozapps/locale/downloads/unknownContentType.properties",
775 getter_AddRefs(bundle
));
779 // if we can't fetch the requested string, try to get "WPS Default"
780 rv
= bundle
->GetStringFromName(aKey
, getter_Copies(title
));
782 rv
= bundle
->GetStringFromName(NS_LITERAL_STRING("wpsDefaultOS2").get(),
783 getter_Copies(title
));
786 if (NS_SUCCEEDED(rv
))
787 result
.Assign(title
);
789 result
.Assign(NS_LITERAL_STRING("WPS Default"));
792 //------------------------------------------------------------------------
794 // converts a native string (presumably a WPS object's title) to
795 // Unicode, removes line breaks, and compresses whitespace
797 static nsresult
AssignTitleString(const char *aTitle
, nsAString
& result
)
799 nsAutoChar16Buffer buffer
;
802 // convert the title to Unicode
803 if (NS_FAILED(MultiByteToWideChar(0, aTitle
, strlen(aTitle
),
805 return NS_ERROR_FAILURE
;
811 // remove line breaks, leading whitespace, & extra embedded whitespace
812 // (primitive, but gcc 3.2.2 doesn't support wchar)
813 for (fSkip
=PR_TRUE
, pSrc
=pDst
=buffer
.Elements(); *pSrc
; pSrc
++) {
814 if (*pSrc
== ' ' || *pSrc
== '\r' || *pSrc
== '\n' || *pSrc
== '\t') {
827 // remove the single trailing space, if needed
828 if (fSkip
&& pDst
> buffer
.Elements())
832 result
.Assign(buffer
.Elements());
836 //------------------------------------------------------------------------
837 // ExtCache implementation
838 //------------------------------------------------------------------------
840 ExtCache::ExtCache() : mCount(0), mSize(0), mExtInfo(0)
845 // the PID is needed to lock/unlock icons
846 DosGetInfoBlocks(&ptib
, &ppib
);
847 mPid
= ppib
->pib_ulpid
;
849 PRUint32 rc
= DosCreateMutexSem(0, (PHMTX
)&mMutex
, 0, 0);
851 ERRMSG(rc
, "DosCreateMutexSem")
854 ExtCache::~ExtCache() {}
856 //------------------------------------------------------------------------
858 // retrieve the WPS's default icon for files with this extension
860 nsresult
ExtCache::GetIcon(const char *aExt
, PRBool aNeedMini
,
863 PRUint32 rc
= DosRequestMutexSem(mMutex
, kMutexTimeout
);
865 ERRMSG(rc
, "DosRequestMutexSem")
866 return NS_ERROR_FAILURE
;
869 ExtInfo
*info
= FindExtension(aExt
);
880 rc
= DosReleaseMutexSem(mMutex
);
882 ERRMSG(rc
, "DosReleaseMutexSem")
884 return (*oIcon
? NS_OK
: NS_ERROR_FAILURE
);
887 //------------------------------------------------------------------------
889 // save the WPS's default icon for files with this extension
891 nsresult
ExtCache::SetIcon(const char *aExt
, PRBool aIsMini
,
894 PRUint32 rc
= DosRequestMutexSem(mMutex
, kMutexTimeout
);
896 ERRMSG(rc
, "DosRequestMutexSem")
897 return NS_ERROR_FAILURE
;
900 ExtInfo
*info
= FindExtension(aExt
, PR_TRUE
);
902 return NS_ERROR_FAILURE
;
904 // the icon has to be made non-deletable or else
905 // it will be destroyed if the WPS terminates
906 if (!WinSetPointerOwner(aIcon
, mPid
, FALSE
)) {
907 ERRPRINTF(info
->ext
, "WinSetPointerOwner failed for %s icon")
908 return NS_ERROR_FAILURE
;
916 ERRPRINTF(info
->ext
, "ExtCache - added icon for %s")
918 rc
= DosReleaseMutexSem(mMutex
);
920 ERRMSG(rc
, "DosReleaseMutexSem")
925 //------------------------------------------------------------------------
927 // retrieve the WPS default handler's title & object handle (if any)
929 nsresult
ExtCache::GetHandler(const char *aExt
, PRUint32
*oHandle
,
932 PRUint32 rc
= DosRequestMutexSem(mMutex
, kMutexTimeout
);
934 ERRMSG(rc
, "DosRequestMutexSem")
935 return NS_ERROR_FAILURE
;
938 nsresult rv
= NS_ERROR_FAILURE
;
939 ExtInfo
*info
= FindExtension(aExt
);
941 // if there's no title, the handle isn't useful
942 if (info
&& info
->title
) {
943 oTitle
.Assign(info
->title
);
944 *oHandle
= info
->handler
;
948 rc
= DosReleaseMutexSem(mMutex
);
950 ERRMSG(rc
, "DosReleaseMutexSem")
955 //------------------------------------------------------------------------
957 // save the WPS default handler's title & object handle (if any)
959 nsresult
ExtCache::SetHandler(const char *aExt
, PRUint32 aHandle
,
962 PRUint32 rc
= DosRequestMutexSem(mMutex
, kMutexTimeout
);
964 ERRMSG(rc
, "DosRequestMutexSem")
965 return NS_ERROR_FAILURE
;
968 nsresult rv
= NS_ERROR_FAILURE
;
969 ExtInfo
*info
= FindExtension(aExt
, PR_TRUE
);
971 // if the title can't be saved, don't save the handle
973 info
->title
= ToNewUnicode(aTitle
);
975 info
->handler
= aHandle
;
977 ERRPRINTF(info
->ext
, "ExtCache - added handler for %s")
981 rc
= DosReleaseMutexSem(mMutex
);
983 ERRMSG(rc
, "DosReleaseMutexSem")
988 //------------------------------------------------------------------------
990 // find the entry for the requested extension; if not found,
991 // create a new entry, expanding the array as needed
993 ExtInfo
*ExtCache::FindExtension(const char *aExt
, PRBool aSet
)
995 // eliminate any leading dot & null extensions
1001 // too long to cache
1002 if (strlen(aExt
) >= 8)
1005 // uppercase extension, then confirm it still fits
1007 strcpy(extUpper
, aExt
);
1008 // XXX WinUpper() can crash with high-memory
1009 // could we just store as-is and instead use stricmp() for
1010 // compare operations?
1011 if (WinUpper(0, 0, 0, extUpper
) >= 8)
1014 // a minor optimization: if we're setting a value, it probably
1015 // belongs to the entry added most recently (i.e. the last one)
1016 if (aSet
&& mCount
&& !strcmp(extUpper
, (&mExtInfo
[mCount
-1])->ext
))
1017 return &mExtInfo
[mCount
-1];
1022 // look for the extension in the array, return if found
1023 for (ctr
= 0, info
= mExtInfo
; ctr
< mCount
; ctr
++, info
++)
1024 if (!strcmp(extUpper
, info
->ext
))
1027 // if a new entry won't fit into the current array, realloc
1028 if (mCount
>= mSize
) {
1029 PRUint32 newSize
= mSize
+ kGrowBy
;
1030 info
= (ExtInfo
*) NS_Realloc(mExtInfo
, newSize
* sizeof(ExtInfo
));
1034 memset(&info
[mSize
], 0, kGrowBy
* sizeof(ExtInfo
));
1039 // point at the next entry & store the extension
1040 info
= &mExtInfo
[mCount
++];
1041 strcpy(info
->ext
, extUpper
);
1046 //------------------------------------------------------------------------
1048 // clear out the cache - since this is only called at shutdown,
1049 // the primary concern is that the icons get unlocked & deleted
1051 void ExtCache::EmptyCache()
1056 PRUint32 rc
= DosRequestMutexSem(mMutex
, kMutexTimeout
);
1058 ERRMSG(rc
, "DosRequestMutexSem")
1062 PRUint32 saveMutex
= mMutex
;
1068 for (ctr
= 0, info
= mExtInfo
; ctr
< mCount
; ctr
++, info
++) {
1070 ERRPRINTF(info
->ext
, "ExtCache - deleting entry for %s")
1073 if (WinSetPointerOwner(info
->icon
, mPid
, TRUE
) == FALSE
||
1074 WinDestroyPointer(info
->icon
) == FALSE
)
1075 ERRPRINTF(info
->ext
, "unable to destroy icon for %s")
1079 if (WinSetPointerOwner(info
->mini
, mPid
, TRUE
) == FALSE
||
1080 WinDestroyPointer(info
->mini
) == FALSE
)
1081 ERRPRINTF(info
->ext
, "unable to destroy mini for %s")
1085 NS_Free(info
->title
);
1093 rc
= DosReleaseMutexSem(saveMutex
);
1095 ERRMSG(rc
, "DosReleaseMutexSem")
1096 rc
= DosCloseMutexSem(saveMutex
);
1098 ERRMSG(rc
, "DosCloseMutexSem")
1101 //------------------------------------------------------------------------
1102 // Module & Factory stuff
1103 //------------------------------------------------------------------------
1105 // this is the "getter proc" for nsRwsServiceConstructor(); it makes a
1106 // single attempt to load the RWS libraries and, if successful, creates
1107 // our singleton object; thereafter, it returns the existing object or
1108 // NS_ERROR_NOT_AVAILABLE
1110 static nsresult
nsRwsServiceInit(nsRwsService
**aClass
)
1112 // init already done - return what we've got or an error
1114 *aClass
= sRwsInstance
;
1116 return NS_ERROR_NOT_AVAILABLE
;
1125 // don't load RWS if "MOZ_NO_RWS" is found in the environment
1126 if (PR_GetEnv("MOZ_NO_RWS"))
1127 return NS_ERROR_NOT_AVAILABLE
;
1132 // try to load RwsCliXX.dll; first, see if the RWS WPS class is
1133 // registered by f/q name - if so, look for RwsCli in the same
1134 // directory; the goal is to consistently use the same pair of
1135 // dlls if the user has multiple copies
1139 // get the list of registered WPS classes
1141 if (!WinEnumObjectClasses(NULL
, &cbClass
))
1142 return NS_ERROR_NOT_AVAILABLE
;
1144 char *pBuf
= (char*)NS_Alloc(cbClass
+ CCHMAXPATH
);
1146 return NS_ERROR_OUT_OF_MEMORY
;
1148 POBJCLASS pClass
= (POBJCLASS
)&pBuf
[CCHMAXPATH
];
1149 if (!WinEnumObjectClasses(pClass
, &cbClass
)) {
1151 return NS_ERROR_NOT_AVAILABLE
;
1156 if (!strcmp(pClass
->pszClassName
, RWSCLASSNAME
))
1158 pClass
= pClass
->pNext
;
1161 // if the class was found & it was registered with a f/q name,
1162 // try to load RwsCliXX from the same directory
1163 if (pClass
&& pClass
->pszModName
[1] == ':') {
1164 strcpy(pBuf
, pClass
->pszModName
);
1165 char *ptr
= strrchr(pBuf
, '\\');
1167 strcpy(ptr
+1, RWSCLIDLL
);
1168 rc
= DosLoadModule(errBuf
, sizeof(errBuf
), pBuf
, &hmod
);
1173 // if RwsCli couldn't be found, look for it on the LIBPATH
1175 rc
= DosLoadModule(errBuf
, sizeof(errBuf
), RWSCLIMOD
, &hmod
);
1177 // the dll couldn't be found, so exit
1179 ERRPRINTF(RWSCLIDLL
, "nsRwsServiceInit - unable to locate %s");
1180 return NS_ERROR_NOT_AVAILABLE
;
1183 // get the addresses of the procs we'll be using;
1184 if (DosQueryProcAddr(hmod
, ORD_RWSCALL
, 0, (PFN
*)&sRwsCall
) ||
1185 DosQueryProcAddr(hmod
, ORD_RWSCALLINDIRECT
,0, (PFN
*)&sRwsCallIndirect
) ||
1186 DosQueryProcAddr(hmod
, ORD_RWSFREEMEM
, 0, (PFN
*)&sRwsFreeMem
) ||
1187 DosQueryProcAddr(hmod
, ORD_RWSGETRESULT
, 0, (PFN
*)&sRwsGetResult
) ||
1188 DosQueryProcAddr(hmod
, ORD_RWSGETARGPTR
, 0, (PFN
*)&sRwsGetArgPtr
) ||
1189 DosQueryProcAddr(hmod
, ORD_RWSCLIENTINIT
, 0, (PFN
*)&sRwsClientInit
) ||
1190 DosQueryProcAddr(hmod
, ORD_RWSGETTIMEOUT
, 0, (PFN
*)&sRwsGetTimeout
) ||
1191 DosQueryProcAddr(hmod
, ORD_RWSSETTIMEOUT
, 0, (PFN
*)&sRwsSetTimeout
) ||
1192 DosQueryProcAddr(hmod
, ORD_RWSCLIENTTERMINATE
, 0, (PFN
*)&sRwsClientTerminate
)) {
1193 DosFreeModule(hmod
);
1194 ERRPRINTF("", "nsRwsServiceInit - DosQueryProcAddr failed%s")
1195 return NS_ERROR_NOT_AVAILABLE
;
1198 // init RWS and have it register the WPS class if needed
1199 rc
= sRwsClientInit(TRUE
);
1201 ERRMSG(rc
, "RwsClientInit")
1202 return NS_ERROR_NOT_AVAILABLE
;
1205 // if the user hasn't set a timeout, reset it to 2 seconds
1206 // (the default is 20 seconds)
1209 rc
= sRwsGetTimeout((PULONG
)¤tTO
, (PULONG
)&userTO
);
1211 ERRMSG(rc
, "RwsGetTimeout")
1214 rc
= sRwsSetTimeout(2);
1216 ERRMSG(rc
, "RwsSetTimeout")
1219 // create an instance of nsRwsService
1220 sRwsInstance
= new nsRwsService();
1221 if (sRwsInstance
== 0)
1222 return NS_ERROR_OUT_OF_MEMORY
;
1224 *aClass
= sRwsInstance
;
1227 // set the class up as a shutdown observer
1228 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
1230 os
->AddObserver(*aClass
, "quit-application", PR_FALSE
);
1235 //------------------------------------------------------------------------
1237 // this is a variation on NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR();
1238 // the only difference is that the _GetterProc returns an nsresult to
1239 // provide a more appropriate error code (typically NS_ERROR_NOT_AVAILABLE)
1241 NS_IMETHODIMP
nsRwsServiceConstructor(nsISupports
*aOuter
, REFNSIID aIID
,
1249 rv
= NS_ERROR_NO_AGGREGATION
;
1253 rv
= nsRwsServiceInit(&inst
);
1254 if (NS_FAILED(rv
)) {
1255 ERRPRINTF(rv
, "==>> nsRwsServiceInit failed - rv= %x");
1259 rv
= inst
->QueryInterface(aIID
, aResult
);
1265 //------------------------------------------------------------------------