qmgr: COM cleanup for the IBackgroundCopyManager iface.
[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,
64                                         (LPVOID *) ppJob);
65     if (FAILED(hres))
66         return hres;
67
68     /* Add a reference to the job to job list */
69     IBackgroundCopyJob_AddRef(*ppJob);
70     job = (BackgroundCopyJobImpl *) *ppJob;
71     EnterCriticalSection(&globalMgr.cs);
72     list_add_head(&globalMgr.jobs, &job->entryFromQmgr);
73     LeaveCriticalSection(&globalMgr.cs);
74     return S_OK;
75 }
76
77 static HRESULT WINAPI BITS_IBackgroundCopyManager_GetJob(IBackgroundCopyManager *iface,
78         REFGUID jobID, IBackgroundCopyJob **ppJob)
79 {
80     FIXME("Not implemented\n");
81     return E_NOTIMPL;
82 }
83
84 static HRESULT WINAPI BITS_IBackgroundCopyManager_EnumJobs(IBackgroundCopyManager *iface,
85         DWORD dwFlags, IEnumBackgroundCopyJobs **ppEnum)
86 {
87     TRACE("\n");
88     return EnumBackgroundCopyJobsConstructor((LPVOID *) ppEnum, iface);
89 }
90
91 static HRESULT WINAPI BITS_IBackgroundCopyManager_GetErrorDescription(IBackgroundCopyManager *iface,
92         HRESULT hResult, DWORD LanguageId, LPWSTR *pErrorDescription)
93 {
94     FIXME("Not implemented\n");
95     return E_NOTIMPL;
96 }
97
98
99 static const IBackgroundCopyManagerVtbl BITS_IBackgroundCopyManager_Vtbl =
100 {
101     BITS_IBackgroundCopyManager_QueryInterface,
102     BITS_IBackgroundCopyManager_AddRef,
103     BITS_IBackgroundCopyManager_Release,
104     BITS_IBackgroundCopyManager_CreateJob,
105     BITS_IBackgroundCopyManager_GetJob,
106     BITS_IBackgroundCopyManager_EnumJobs,
107     BITS_IBackgroundCopyManager_GetErrorDescription
108 };
109
110 BackgroundCopyManagerImpl globalMgr = {
111     { &BITS_IBackgroundCopyManager_Vtbl },
112     { NULL, -1, 0, 0, 0, 0 },
113     NULL,
114     LIST_INIT(globalMgr.jobs)
115 };
116
117 /* Constructor for instances of background copy manager */
118 HRESULT BackgroundCopyManagerConstructor(IUnknown *pUnkOuter, LPVOID *ppObj)
119 {
120     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
121     *ppObj = &globalMgr;
122     return S_OK;
123 }
124
125 DWORD WINAPI fileTransfer(void *param)
126 {
127     BackgroundCopyManagerImpl *qmgr = &globalMgr;
128     HANDLE events[2];
129
130     events[0] = stop_event;
131     events[1] = qmgr->jobEvent;
132
133     for (;;)
134     {
135         BackgroundCopyJobImpl *job, *jobCur;
136         BOOL haveJob = FALSE;
137
138         /* Check if it's the stop_event */
139         if (WaitForMultipleObjects(2, events, FALSE, INFINITE) == WAIT_OBJECT_0)
140         {
141             LIST_FOR_EACH_ENTRY_SAFE(job, jobCur, &qmgr->jobs, BackgroundCopyJobImpl, entryFromQmgr)
142             {
143                 list_remove(&job->entryFromQmgr);
144                 IBackgroundCopyJob_Release((IBackgroundCopyJob *) job);
145             }
146             return 0;
147         }
148
149         /* Note that other threads may add files to the job list, but only
150            this thread ever deletes them so we don't need to worry about jobs
151            magically disappearing from the list.  */
152         EnterCriticalSection(&qmgr->cs);
153
154         LIST_FOR_EACH_ENTRY_SAFE(job, jobCur, &qmgr->jobs, BackgroundCopyJobImpl, entryFromQmgr)
155         {
156             if (job->state == BG_JOB_STATE_ACKNOWLEDGED || job->state == BG_JOB_STATE_CANCELLED)
157             {
158                 list_remove(&job->entryFromQmgr);
159                 IBackgroundCopyJob_Release((IBackgroundCopyJob *) job);
160             }
161             else if (job->state == BG_JOB_STATE_QUEUED)
162             {
163                 haveJob = TRUE;
164                 break;
165             }
166             else if (job->state == BG_JOB_STATE_CONNECTING
167                      || job->state == BG_JOB_STATE_TRANSFERRING)
168             {
169                 ERR("Invalid state for job %p: %d\n", job, job->state);
170             }
171         }
172
173         if (!haveJob)
174             ResetEvent(qmgr->jobEvent);
175
176         LeaveCriticalSection(&qmgr->cs);
177
178         if (haveJob)
179             processJob(job);
180     }
181 }