Найти глобальный атом из частичной строки

Я могу создать Глобальный Атом, используя GlobalAddAtom и я могу найти этот атом снова, используя GlobalFindAtom если я уже знаю строку, связанную с атомом. Но есть ли способ найти все атомы, чья связанная строка соответствует данной частичной строке?

Например, допустим, у меня есть атом, строка которого "Hello, World!" Как я могу позже найти этот атом, выполнив поиск "Hello"?

2 ответа

Решение

К сожалению, описываемое вами поведение невозможно для таблиц Atom. Это связано с тем, что таблицы Atom в Windows в основном являются хэш-таблицами, а процесс отображения обрабатывает строки целиком, а не по частям.

Конечно, это звучит так, как будто это возможно, как указано в документации MSDN:

Приложения могут также использовать таблицы локальных атомов для экономии времени при поиске конкретной строки. Чтобы выполнить поиск, приложению нужно только поместить строку поиска в таблицу атомов и сравнить полученный атом с атомами в соответствующих структурах. Сравнение атомов обычно быстрее, чем сравнение строк.

Однако они имеют в виду точные совпадения. Это ограничение, вероятно, устарело по сравнению с тем, что возможно с ресурсами, доступными в настоящее время для программного обеспечения. Тем не менее, Atoms были доступны еще в Win16, и в то время это средство позволяло приложениям эффективно управлять строковыми данными в минимальном объеме памяти. Атомы по-прежнему используются в настоящее время для управления именами классов окон и все еще обеспечивают приличные преимущества в уменьшении занимаемой площади нескольких хранимых копий строк.

Если вам необходимо эффективно хранить строковые данные и иметь возможность сканирования путем частичных начальных совпадений, дерево суффиксов, вероятно, удовлетворит или превысит ваши потребности.

Это на самом деле можно сделать, но только путем сканирования их всех. В LINQPad 5 это можно сделать за 0,025 секунды на моем компьютере, поэтому это довольно быстро. Вот пример реализации:

void Main()
{
  const string atomPrefix = "Hello";
  const int bufferSize = 1024;
  ushort smallestAtomIndex = 0XC000;
  var buffer = new StringBuilder(bufferSize);
  var results = new List<string>();
  for (ushort atomIndex = smallestAtomIndex; atomIndex < ushort.MaxValue; atomIndex++)
  {
    var resultLength = GlobalGetAtomName(atomIndex, buffer, bufferSize);
    if (buffer.ToString().StartsWith(atomPrefix))
    {
      results.Add($"{buffer} - {atomIndex}");
    }
    buffer.Clear();
  }

  results.Dump();
}

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern uint GlobalGetAtomName(ushort atom, StringBuilder buffer, int size);
Другие вопросы по тегам