Если вы прочитали документацию , то есть javadoc из ListIterator.add()
, вы увидите:
Вставляет указанный элемент в список (необязательно) операция). Элемент вставляется непосредственно перед элементом, который будет возвращен
blockquote>next()
, если таковой имеется, и после элемента, который будет возвращенprevious()
, если таковой имеется. (Если список не содержит элементов, новый элемент становится единственным элементом в списке.) Новый элемент вставляется перед неявным курсором: последующий вызовnext
не будет затронут, а последующий вызов [ 116] вернет новый элемент . (Этот вызов увеличивается на единицу значения, которое будет возвращено вызовом кnextIndex
илиpreviousIndex
.)Таким образом, чередующиеся вызовы к
previous()
иadd()
сохранят вставку значения в той же позиции в списке, и, следовательно, никогда не закончится (пока не закончится память).Чтобы показать, что происходит, попробуйте следующий код:
public static void main(String[] args) { List
list = new ArrayList<>(Arrays.asList(10, 20, 30, 40)); ListIterator listIter = list.listIterator(list.size()); print(list, listIter); // Iterator is at end (after 40) System.out.println("previous(): " + listIter.previous()); // prints: 40 print(list, listIter); // Iterator is between 30 and 40 for (int i = 39; i >= 31; i--) { listIter.add(i); System.out.printf("add(i)%n", i); print(list, listIter); System.out.println("previous(): " + listIter.previous()); print(list, listIter); } } static void print(List list, ListIterator listIter) { for (Integer i : list) System.out.printf("%5d", i); System.out.printf("%n%" + (listIter.nextIndex() * 5 + 2) + "s%n", "^"); } Вывод
10 20 30 40 ^ previous(): 40 10 20 30 40 ^ add(i) 10 20 30 39 40 ^ previous(): 39 10 20 30 39 40 ^ add(i) 10 20 30 38 39 40 ^ previous(): 38 10 20 30 38 39 40 ^ add(i) 10 20 30 37 38 39 40 ^ previous(): 37 10 20 30 37 38 39 40 ^ add(i) 10 20 30 36 37 38 39 40 ^ previous(): 36 10 20 30 36 37 38 39 40 ^ add(i) 10 20 30 35 36 37 38 39 40 ^ previous(): 35 10 20 30 35 36 37 38 39 40 ^ add(i) 10 20 30 34 35 36 37 38 39 40 ^ previous(): 34 10 20 30 34 35 36 37 38 39 40 ^ add(i) 10 20 30 33 34 35 36 37 38 39 40 ^ previous(): 33 10 20 30 33 34 35 36 37 38 39 40 ^ add(i) 10 20 30 32 33 34 35 36 37 38 39 40 ^ previous(): 32 10 20 30 32 33 34 35 36 37 38 39 40 ^ add(i) 10 20 30 31 32 33 34 35 36 37 38 39 40 ^ previous(): 31 10 20 30 31 32 33 34 35 36 37 38 39 40 ^
Вот способ ленивого человека решить эту проблему: Используйте heat
от WiX 3.0.
, Если Вам генерировали библиотеку типов автоматически и установленный через regasm, heat
, может взять .tlb в качестве аргумента в
heat file c:\my\path\to\my.tlb -out tlb.wxs
, Это генерирует весь typelib и соединит интерфейсом с элементами, которые необходимо зарегистрировать. Это не решит проблему необходимости знать их заранее, и она не решит проблему изменения GUID, когда версия изменений блока (даже если интерфейс не сделает - который является единственным временем, Вы, как предполагается, изменяете ее), но это получит Вас отчасти там.
Следующий прием может помочь со сбором урожая любых изменений реестра и превращением их в wxs файл, включая typelib элемент, который Вы после.
Первый, возвратите свой реестр в состоянии, где библиотека типов не была зарегистрирована:
c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\regasm.exe /tlb /u mylib.dll
Экспорт это чистое состояние реестра к hklm-before.reg:
c:\WINDOWS\system32\reg.exe export HKLM hklm-before.reg
Регистр библиотека типов снова:
c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\regasm.exe /tlb mylib.dll
Экспорт новое состояние реестра к hklm-after.reg:
c:\WINDOWS\system32\reg.exe export HKLM hklm-after.reg
Теперь у нас есть два текстовых файла, hklm-before.reg и hklm-after.reg. Создают файл diff.reg, который только содержит соответствующие различия между ними. Можно найти различия легко с diffing инструментом. Мне нравится использовать различный инструмент, включенный в TortoiseSVN, так как я уже использую это каждый день. (WinDiff, кажется, не работает хорошо в этом случае из-за кодирующих текст проблем.)
Мы можем теперь преобразовать diff.reg в .wxs путем вызова heat.exe
с эти reg
команда. (Требует wix 3.5 или более новый.)
heat reg diff.reg -out typelib.wxs
Это похоже для регистрации Библиотеки типов, лучший , путь состоял бы в том, чтобы генерировать собственный IDL или файл ODL, который будет содержать GUID. Typelib, сгенерированные непосредственно от блока, являются [я] зависимым [/i] на номерах версий блока: GUID сгенерированы на основе той информации, даже если интерфейс не изменился. Visual Studio использует regasm, чтобы зарегистрировать и генерировать typelib. Под этим это использует RegisterTypeLib, вызов win32. Используя typelib элемент, кажется, делает что-то подобное. Отрицательный результат.
Однако! Создание библиотеки типов вручную является болезненным. Возможно получить те GUID иначе: рытье их из typelib и создания элементов самостоятельно.
у Larry Osterman есть информация, это необходимо: существуют определенные ключи реестра, которые должны быть установлены. Можно сделать тех, которые имеют таблицу Registry (и в Wix3, который означает элементы RegistryValue.) Прием здесь получает GUID: любой старый GUID не будет работать. Обычно, получение GUID является просто вопросом взгляда в IDL для Вашей библиотеки (Вы записали свой собственный IDL, правильно?:)).
, Если Вы не записали IDL или файл ODL для компиляции в typelib, они все еще существуют в файле. Microsoft обеспечивает несколько удобных инструментов: LoadTypeLibEx и интерфейс ITypeLib. С этими интерфейсами можно просмотреть библиотеку типов и получить все виды информации. Как мы просматриваем библиотеку?
я просто смотрел на то, как Regasm сделал это! Быстрое демонтирует позже, и мы находим, что regasm записан в C# также. Славный день. Я запустил проект, и с несколькими операторами использования и PInvoke позже, мы имеем:
using System.Runtime.InteropServices; // for struct marshaling
using System.Runtime.InteropServices.ComTypes; // for the ITypeLib + related types
// TYPELIBATTR lives in two places: Interop and ComTypes, but the one
// in Interop is deprecated.
using TYPELIBATTR = System.Runtime.InteropServices.ComTypes.TYPELIBATTR;
/// <summary>
/// The registry kind enumeration for LoadTypeLibEx. This must be made
/// here, since it doesn't exist anywhere else in C# afaik. This is found
/// here: http://msdn.microsoft.com/en-us/library/ms221159.aspx
/// </summary>
enum REGKIND
{
REGKIND_DEFAULT,
REGKIND_REGISTER,
REGKIND_NONE
}
// and this is how we get the library.
[DllImport("oleaut32.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
private static extern void LoadTypeLibEx(string strTypeLibName, REGKIND regKind, out ITypeLib TypeLib);
Ух! Как только у нас есть это, мы должны переместиться по структуре. Это взаимодействует с неуправляемыми ресурсами, поэтому подготовьтесь быть Marshal
материал луга вокруг.
ITypeLib lib = null;
LoadTypeLibEx(Value, REGKIND.REGKIND_NONE, out lib);
IntPtr libInfoPtr = IntPtr.Zero;
lib.GetLibAttr(out libInfoPtr);
TYPELIBATTR libInfo =
(TYPELIBATTR) Marshal.PtrToStructure(libInfoPtr, typeof(TYPELIBATTR));
int typeCount = lib.GetTypeInfoCount();
for (int i = 0; i < typeCount; ++i)
{
ITypeInfo info;
lib.GetTypeInfo(i, out info);
IntPtr typeDescrPtr = IntPtr.Zero;
info.GetTypeAttr(out typeDescrPtr);
TYPELIBATTR type =
(TYPELIBATTR)Marshal.PtrToStructure(typeDescrPtr, typeof(TYPELIBATTR));
// get GUID, other info from the specific type
}
lib.ReleaseTLibAttr(libInfoPtr);
libInfoPtr = IntPtr.Zero;
Ух. Так, необходимо написать некоторый код для извлечения информации. Как только Вы делаете, необходимо заполнить ту информацию в Записи Registy, как определено Larry Osterman .
, Конечно, Вы могли избежать что шаг путем простой записи собственного файла IDL для начала. Выбор в боли: Вам решать!