msvcrt: Return child exit code in _pclose function.
[wine] / dlls / qmgr / qmgr.c
1 /*
2  * Queue Manager (BITS) core functions
3  *
4  * Copyright 2007, 2008 Google (Roy Shea, Dan Hipschman)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "qmgr.h"
22 #include "wine/debug.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(qmgr);
25
26 BackgroundCopyManagerImpl globalMgr;
27
28 static HRESULT WINAPI BITS_IBackgroundCopyManager_QueryInterface(IBackgroundCopyManager *iface,
29         REFIID riid, void **ppv)
30 {
31     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppv);
32
33     if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IBackgroundCopyManager))
34     {
35         *ppv = iface;
36         IBackgroundCopyManager_AddRef(iface);
37         return S_OK;
38     }
39
40     *ppv = NULL;
41     return E_NOINTERFACE;
42 }
43
44 static ULONG WINAPI BITS_IBackgroundCopyManager_AddRef(IBackgroundCopyManager *iface)
45 {
46     return 2;
47 }
48
49 static ULONG WINAPI BITS_IBackgroundCopyManager_Release(IBackgroundCopyManager *iface)
50 {
51     return 1;
52 }
53
54 /*** IBackgroundCopyManager interface methods ***/
55
56 static HRESULT WINAPI BITS_IBackgroundCopyManager_CreateJob(IBackgroundCopyManager *iface,
57         LPCWSTR DisplayName, BG_JOB_TYPE Type, GUID *pJobId, IBackgroundCopyJob **ppJob)
58 {
59     BackgroundCopyJobImpl *job;
60     HRESULT hres;
61     TRACE("\n");
62
63     hres = BackgroundCopyJobConstructor(DisplayName, Type, pJobId, &job);
64     if (FAILED(hres))
65         return hres;
66
67     /* Add a reference to the job to job list */
68     *ppJob = (IBackgroundCopyJob*)&job->IBackgroundCopyJob2_iface;
69     IBackgroundCopyJob_AddRef(*ppJob);
70     EnterCriticalSection(&globalMgr.cs);
71     list_add_head(&globalMgr.jobs, &job->entryFromQmgr);
72     LeaveCriticalSection(&globalMgr.cs);
73     return S_OK;
74 }
75
76 static HRESULT WINAPI BITS_IBackgroundCopyManager_GetJob(IBackgroundCopyManager *iface,
77         REFGUID jobID, IBackgroundCopyJob **ppJob)
78 {
79     FIXME("Not implemented\n");
80     return E_NOTIMPL;
81 }
82
83 static HRESULT WINAPI BITS_IBackgroundCopyManager_EnumJobs(IBackgroundCopyManager *iface,
84         DWORD dwFlags, IEnumBackgroundCopyJobs **ppEnum)
85 {
86     TRACE("\n");
87     return enum_copy_job_create(&globalMgr, ppEnum);
88 }
89
90 static HRESULT WINAPI BITS_IBackgroundCopyManager_GetErrorDescription(IBackgroundCopyManager *iface,
91         HRESULT hResult, DWORD LanguageId, LPWSTR *pErrorDescription)
92 {
93     FIXME("Not implemented\n");
94     return E_NOTIMPL;
95 }
96
97
98 static const IBackgroundCopyManagerVtbl BITS_IBackgroundCopyManager_Vtbl =
99 {
100     BITS_IBackgroundCopyManager_QueryInterface,
101     BITS_IBackgroundCopyManager_AddRef,
102     BITS_IBackgroundCopyManager_Release,
103     BITS_IBackgroundCopyManager_CreateJob,
104     BITS_IBackgroundCopyManager_GetJob,
105     BITS_IBackgroundCopyManager_EnumJobs,
106     BITS_IBackgroundCopyManager_GetErrorDescription
107 };
108
109 BackgroundCopyManagerImpl globalMgr = {
110     { &BITS_IBackgroundCopyManager_Vtbl },
111     { NULL, -1, 0, 0, 0, 0 },
112     NULL,
113     LIST_INIT(globalMgr.jobs)
114 };
115
116 /* Constructor for instances of background copy manager */
117 HRESULT BackgroundCopyManagerConstructor(IUnknown *pUnkOuter, LPVOID *ppObj)
118 {
119     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
120     *ppObj = &globalMgr;
121     return S_OK;
122 }
123
124 DWORD WINAPI fileTransfer(void *param)
125 {
126     BackgroundCopyManagerImpl *qmgr = &globalMgr;
127     HANDLE events[2];
128
129     events[0] = stop_event;
130     events[1] = qmgr->jobEvent;
131
132     for (;;)
133     {
134         BackgroundCopyJobImpl *job, *jobCur;
135         BOOL haveJob = FALSE;
136
137         /* Check if it's the stop_event */
138         if (WaitForMultipleObjects(2, events, FALSE, INFINITE) == WAIT_OBJECT_0)
139         {
140             LIST_FOR_EACH_ENTRY_SAFE(job, jobCur, &qmgr->jobs, BackgroundCopyJobImpl, entryFromQmgr)
141             {
142                 list_remove(&job->entryFromQmgr);
143                 IBackgroundCopyJob2_Release(&job->IBackgroundCopyJob2_iface);
144             }
145             return 0;
146         }
147
148         /* Note that other threads may add files to the job list, but only
149            this thread ever deletes them so we don't need to worry about jobs
150            magically disappearing from the list.  */
151         EnterCriticalSection(&qmgr->cs);
152
153         LIST_FOR_EACH_ENTRY_SAFE(job, jobCur, &qmgr->jobs, BackgroundCopyJobImpl, entryFromQmgr)
154         {
155             if (job->state == BG_JOB_STATE_ACKNOWLEDGED || job->state == BG_JOB_STATE_CANCELLED)
156             {
157                 list_remove(&job->entryFromQmgr);
158                 IBackgroundCopyJob2_Release(&job->IBackgroundCopyJob2_iface);
159             }
160             else if (job->state == BG_JOB_STATE_QUEUED)
161             {
162                 haveJob = TRUE;
163                 break;
164             }
165             else if (job->state == BG_JOB_STATE_CONNECTING
166                      || job->state == BG_JOB_STATE_TRANSFERRING)
167             {
168                 ERR("Invalid state for job %p: %d\n", job, job->state);
169             }
170         }
171
172         if (!haveJob)
173             ResetEvent(qmgr->jobEvent);
174
175         LeaveCriticalSection(&qmgr->cs);
176
177         if (haveJob)
178             processJob(job);
179     }
180 }