1 | /* |
2 | * $Id: ComRegistryHelper.java,v 1.3 2006/02/01 04:48:37 hastings Exp $ |
3 | * |
4 | * (c) Copyright, Moebius Solutions, Inc., 2004 |
5 | * |
6 | * All Rights Reserved |
7 | * |
8 | * This material may be reproduced by or for the U. S. Government |
9 | * pursuant to the copyright license under the clause at |
10 | * DFARS 252.227-7014 (OCT 2001). |
11 | */ |
12 | package com.moesol.bindings.platform_sdk.component_services; |
13 | |
14 | |
15 | import java.util.ArrayList; |
16 | |
17 | import com.moesol.bindings.DispatchJavaCoClass; |
18 | import com.moesol.bindings.platform_sdk.windows_api.HKEY; |
19 | import com.moesol.bindings.platform_sdk.windows_api.PlatformSDK; |
20 | import com.moesol.bindings.platform_sdk.windows_api.Win32Exception; |
21 | |
22 | public class ComRegistryHelper { |
23 | |
24 | public static class Value { |
25 | final String key; |
26 | final String value_name; |
27 | final String value_value; |
28 | |
29 | public Value(String k, String vn, String vv) { |
30 | key = k; |
31 | value_name = vn; |
32 | value_value = vv; |
33 | } |
34 | } |
35 | |
36 | /** |
37 | * Register a java class as a COM object server. |
38 | * The server defaults to an {@code InprocServer32} with an {@code Apartment} threading model. |
39 | * |
40 | * @param java_server_class |
41 | * @param group_name |
42 | */ |
43 | public static void registerServer(Class java_server_class, String group_name) { |
44 | registerServer(java_server_class, group_name, COM.ThreadingModel_Apartment); |
45 | } |
46 | |
47 | /** |
48 | * Register a java class as a COM object server. The server defaults to an |
49 | * {@code InprocServer32}. |
50 | * |
51 | * @param java_server_class |
52 | * @param group_name |
53 | * @param threading |
54 | * COM threading model, one of COM.ThreadingModel_Apartment, |
55 | * ThreadingModel_Both, ThreadingModel_Free, |
56 | * ThreadingModel_Neutral, or null (for Single) |
57 | */ |
58 | public static void registerServer(Class java_server_class, String group_name, String threading) { |
59 | DispatchJavaCoClass jc = DispatchJavaCoClass.forClass(java_server_class); |
60 | GUID clsid = jc.getUuid(); |
61 | |
62 | ArrayList make_keys = ComRegistryHelper.computeInprocServer32Keys(clsid, jc.getImplementedCategories()); |
63 | makeRegistryKeys(make_keys); |
64 | |
65 | ArrayList values = computeInprocServer32Values(java_server_class, group_name, clsid, threading); |
66 | makeRegistryValues(values); |
67 | |
68 | // TODO roll-back any keys we created if we fail later |
69 | } |
70 | |
71 | /** |
72 | * Make registry keys and values. Key names are taken from the Value objects. |
73 | * |
74 | * @param values {@code ArrayList} of {@code Value} objects |
75 | */ |
76 | public static void makeRegistryKeysAndValues(ArrayList values) { |
77 | ArrayList keys = new ArrayList(); |
78 | for (int i = 0; i < values.size(); i++) { |
79 | Value v = (Value)values.get(i); |
80 | keys.add(v.key); |
81 | } |
82 | makeRegistryKeys(keys); |
83 | makeRegistryValues(values); |
84 | } |
85 | |
86 | /** |
87 | * Make registry keys. The keys should be ordered so that all |
88 | * parent keys are created first. For example, of you want to |
89 | * create HKEY_LOCAL_MACHINE\Software\Acme\Foo\Bar, you should |
90 | * provide ["Software\\Acme", "Software\\Acme\\Foo", "Software\\Acme\\Foo\\Bar"] |
91 | * |
92 | * @param make_keys {@code ArrayList} of {@code String} paths for keys. |
93 | */ |
94 | public static void makeRegistryKeys(ArrayList make_keys) { |
95 | for (int i = 0; i < make_keys.size(); i++) { |
96 | ComRegistryHelper.makeRegistryKey((String)make_keys.get(i)); |
97 | } |
98 | } |
99 | |
100 | /** |
101 | * Delete registry keys. This keys are processed in reverse order so |
102 | * that child keys are deleted first. Therefore, the array list should |
103 | * be in the same order as the one used for {@code makeRgistryKeys}. |
104 | * |
105 | * @param make_keys {@code ArrayList} of {@code String} |
106 | */ |
107 | public static void deleteRegistryKeys(ArrayList make_keys) { |
108 | for (int i = make_keys.size() - 1; i >= 0; i--) { |
109 | deleteRegistryKey((String)make_keys.get(i)); |
110 | } |
111 | } |
112 | |
113 | /** |
114 | * Delete registry keys. This keys are processed in reverse order so |
115 | * that child keys are deleted first. Therefore, the array list should |
116 | * be in the same order as the one used for {@code makeRgistryKeys}. |
117 | * |
118 | * @param make_keys {@code ArrayList} of {@code Value}s |
119 | */ |
120 | public static void deleteRegistryKeysFromValues(ArrayList make_keys) { |
121 | for (int i = make_keys.size() - 1; i >= 0; i--) { |
122 | Value value = (Value)make_keys.get(i); |
123 | deleteRegistryKey(value.key); |
124 | } |
125 | } |
126 | |
127 | /** |
128 | * Make registry values. The keys for the values should already exist. |
129 | * |
130 | * @param values {@code ArrayList} of {@code Value} objects |
131 | */ |
132 | public static void makeRegistryValues(ArrayList values) { |
133 | for (int i = 0; i < values.size(); i++) { |
134 | ComRegistryHelper.setRegistryValue((Value)values.get(i)); |
135 | } |
136 | } |
137 | |
138 | /** |
139 | * Deletes the registry entries that were added by registerServer. |
140 | * |
141 | * @param java_server_class |
142 | */ |
143 | public static void unregisterServer(Class java_server_class) { |
144 | DispatchJavaCoClass jc = DispatchJavaCoClass.forClass(java_server_class); |
145 | GUID clsid = jc.getUuid(); |
146 | ArrayList make_keys = ComRegistryHelper.computeInprocServer32Keys(clsid, jc.getImplementedCategories()); |
147 | |
148 | deleteRegistryKeys(make_keys); |
149 | } |
150 | |
151 | /** |
152 | * Make a registry key. Parent keys must already exist. |
153 | * |
154 | * @param key_path |
155 | */ |
156 | private static void makeRegistryKey(String key_path) { |
157 | HKEY out_key[] = { null }; |
158 | PlatformSDK.RegCreateKeyEx( |
159 | PlatformSDK.HKEY_CLASSES_ROOT, |
160 | key_path, |
161 | 0, |
162 | null, |
163 | 0, |
164 | PlatformSDK.REG_CREATED_NEW_KEY, |
165 | null, |
166 | out_key, |
167 | null); |
168 | out_key[0].Close(); |
169 | } |
170 | |
171 | private static void deleteRegistryKey(String key) { |
172 | try { |
173 | PlatformSDK.RegDeleteKey(PlatformSDK.HKEY_CLASSES_ROOT, key); |
174 | } catch (Win32Exception we) { |
175 | if (we.getLRESULT() != PlatformSDK.ERROR_FILE_NOT_FOUND) { |
176 | throw we; |
177 | } |
178 | } |
179 | } |
180 | |
181 | /** |
182 | * @param values |
183 | */ |
184 | private static void setRegistryValue(Value value) { |
185 | HKEY[] out_key = { null }; |
186 | PlatformSDK.RegOpenKeyEx(PlatformSDK.HKEY_CLASSES_ROOT, value.key, 0, PlatformSDK.KEY_SET_VALUE, out_key); |
187 | try { |
188 | PlatformSDK.RegSetValueEx(out_key[0], value.value_name, value.value_value); |
189 | } finally { |
190 | out_key[0].Close(); |
191 | } |
192 | } |
193 | |
194 | /** |
195 | * @param java_server_class java class servering clsid |
196 | * @param group_name classloader group name to group this class into |
197 | * @param clsid GUID of class to register |
198 | * @return ArrayList<Value> values to add to the registry |
199 | */ |
200 | private static ArrayList computeInprocServer32Values(Class java_server_class, String group_name, GUID clsid, String threading) { |
201 | ArrayList result = new ArrayList(); |
202 | result.add(new Value("CLSID\\" + clsid.toString(), null, getCannonicalName(java_server_class))); |
203 | result.add(new Value("CLSID\\" + clsid.toString() + "\\InProcServer32", null, COM.getBindingsPath())); |
204 | result.add(new Value("CLSID\\" + clsid.toString() + "\\InProcServer32", "Class", java_server_class.getName())); |
205 | result.add(new Value("CLSID\\" + clsid.toString() + "\\InProcServer32", "Group", group_name)); |
206 | if (threading != null) { |
207 | result.add(new Value("CLSID\\" + clsid.toString() + "\\InProcServer32", "ThreadingModel", threading)); |
208 | } |
209 | return result; |
210 | } |
211 | |
212 | private static String getCannonicalName(Class c) { |
213 | String long_name = c.getName(); |
214 | int dot = long_name.lastIndexOf('.'); |
215 | return long_name.substring(dot + 1); |
216 | } |
217 | |
218 | /** |
219 | * @param clsid |
220 | * @param impl_cat |
221 | * @param keys |
222 | */ |
223 | private static void addImplementedCategoryKeys(GUID clsid, GUID[] impl_cat, ArrayList keys) { |
224 | if (null == impl_cat) { |
225 | return; |
226 | } |
227 | for (int i = 0; i < impl_cat.length; i++) { |
228 | if (i == 0) { |
229 | keys.add("CLSID\\" + clsid.toString() + "\\Implemented Categories"); |
230 | } |
231 | keys.add("CLSID\\" + clsid.toString() + "\\Implemented Categories\\" + impl_cat[i]); |
232 | } |
233 | } |
234 | |
235 | /** |
236 | * @param clsid |
237 | * @return array of keys |
238 | */ |
239 | private static ArrayList computeInprocServer32Keys(GUID clsid, GUID[] impl_cat) { |
240 | ArrayList result = new ArrayList(); |
241 | result.add("CLSID\\" + clsid.toString()); |
242 | result.add("CLSID\\" + clsid.toString() + "\\InprocServer32"); |
243 | |
244 | addImplementedCategoryKeys(clsid, impl_cat, result); |
245 | |
246 | return result; |
247 | } |
248 | |
249 | } |