Я смотрел на код JavaScript других людей, и я заметил, что многие программисты склонны создавать функции, которые могли быть объединены с функциями, которые называют их. Один пример - это; функция 'initWebGL' могла быть объединена с функцией 'запуска', и она будет функционировать то же. Другой пример находится в источнике этого, где функция 'галочка', которую называют каждыми 15 миллисекундами, выполняет вызовы к двум другим функциям, которые могут точно также быть объединены с 'галочкой'. Я понимаю организационные качества этого, но мне любопытно на предмет эффекта на производительность. Делает эту хорошую практику, особенно полагая, что JavaScript является интерпретируемым языком?
Вот какой код, который работает для меня:
public struct KBDLLHOOKSTRUCT
{
public Int32 vkCode;
public Int32 scanCode;
public Int32 flags;
public Int32 time;
public IntPtr dwExtraInfo;
}
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
KBDLLHOOKSTRUCT kbd = (KBDLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
Debug.WriteLine(kbd.vkCode); // ***** your code here *****
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
Решающее отличие от вашего кода заключается в том, что я вызываю перегрузку Marshal.PtrToStructure (IntPtr, Type), а не перегрузку (IntPtr, object). И я думаю, здесь все пошло не так для тебя. Поскольку при вызове перегрузки (IntPtr, объект) со структурой возникает следующая ошибка:
System.ArgumentException: структура не должна быть классом значений.
Очевидным исправлением этой ошибки является изменение KBDLLLHOOKSTRUCT на класс (ссылочный тип) вместо структуры (тип значения):
public class KBDLLHOOKSTRUCT // not necessarily the right solution!
Однако это приводит к ошибке, которая означает, что MSDN означает "компоновка параметра strucureType не является последовательной или явной".
System.ArgumentException: указанная структура
Я предполагаю, что именно здесь вы находитесь сейчас, с KBDLLHOOKSTRUCT, объявленным как класс, и получением ошибки "no layout information". Существует два способа решения этой проблемы.
Во-первых, в соответствии с комментарием Эрика Ло, вы можете сохранить свой вызов Marshal.PtrToStructure как есть, сохранить KBDLLHOOKSTRUCT как класс и добавить информацию о макете в KBDLLHOOKSTRUCT:
[StructLayout(LayoutKind.Sequential)]
public class KBDLLHOOKSTRUCT { ... }
Во-вторых, согласно моему образцу кода выше, можно изменить KBDLLHOOKSTRUCT на struct
вместо class
и изменить вызов Marshal.PtrToStructure на перегрузку (IntPtr, Type):
public struct KBDLLHOOKSTRUCT { ... }
KBDLLHOOKSTRUCT kbd = (KBDLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
(В этом случае в структуру KBDLLHOOKSTRUCT можно добавить атрибут [StructLayout (LayoutKind.Sequential)]
. Это технически избыточно, но может помочь читателям вашего кода распознать KBDLLHOOKSTRUCT как чувствительный к макету тип взаимодействия.)
Оба эти решения работают для меня в (по общему признанию, простом) тесте. Из двух я бы рекомендовал второй, потому что Win32/C структуры условно объявляются как struct
в сценариях P/Invoke - и если ничто другое, имя, которое заканчивается в STRUCT, вероятно, должно быть структурой, а не классом!
Наконец, позвольте мне упомянуть альтернативный подход.
Вместо того, чтобы объявить LowLevelKeyboardProc как получение IntPtr как его lParam, возможно объявить это как получение касательно KBDLLHOOKSTRUCT
(где KBDLLHOOKSTRUCT структура
, не класс
). Это также требует внесения изменений в CallNextAdingEx, но результатом является упрощение использования информации KBDLLHOOKSTRUCT путем полного исключения вызова Marshal. Использование параметра ref также означает, что вы можете записать в структуру (что я знаю из других вопросов является вашей целью) и не нужно упаковывать его обратно после написания:
private delegate IntPtr LowLevelKeyboardProc(
int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT kbd);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT kbd)
{
Debug.WriteLine(kbd.vkCode); // look! no marshalling!
return CallNextHookEx(_hookID, nCode, wParam, ref kbd);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, ref KBDLLHOOKSTRUCT kbd);
(Я, вероятно, должен предупредить вас, однако, что когда я пытался изменить kbd.vkCode, это на самом деле не повлияло на то, что появилось в текстовых полях и т.д. Я не знаю достаточно о низкоуровневых клавиатурных крючках, чтобы знать, почему нет или что мне нужно сделать, чтобы это сработало; извините.)
-121--3052352-(Хорошо второй раз повезло..)
К вашему сведению, здесь есть еще один вопрос выполнить подключение ()на определенном сетевом адаптере по тем же линиям...
В соответствии с Cable Guy
Windows XP и Windows Server ® 2003 использовать слабую модель хоста для отправки и получает для всех IPv4 интерфейсов и сильная модель хоста для отправки и принимает для всех интерфейсов IPv6. Вы не удается настроить это поведение. Стек TCP/IP следующего поколения в Windows Vista и Windows Server 2008 поддерживает надежные серверные передачи и получает как для IPv4, так и для IPv6 по умолчанию для всех интерфейсов, кроме Интерфейс туннелирования Teredo для Реле для хоста Teredo.
Поэтому, чтобы ответить на ваш вопрос (правильно, на этот раз) в Windows XP и Windows Server 2003 IP4 нет, но для IP6 да. А для Windows Vista и Windows 2008 да (за исключением некоторых обстоятельств).
Также от http://www.codeguru.com/forum/showthread.php?t=487139
В Windows вызов bind () влияет на выбор платы только входящий трафик, не исходящий трафик. Таким образом, на клиент, работающий в многопользовательской системе (т.е. более одной интерфейсной платы), это сетевой стек, который выбирает карта для использования, и она делает выбор на основе только IP-адрес назначения, который, в свою очередь, основан в таблице маршрутизации. Вызов для привязки () не повлияет на выбор карты в любом случае.
Это связано с что-то называемое «слабой конечной системой» («Слабая E/S») модель. Vista изменен на сильная модель E/S, поэтому проблема может не возникает в Vista . Но все предыдущие в версиях Windows использовался слабый E/S модель.
Со слабой моделью E/S это таблица маршрутизации, которая определяет, какая плата используется для исходящего трафика в многосетевая система.
Проверьте, предлагают ли эти потоки некоторые insight:
"Привязка локального сокета к многоканальному узел в Windows XP не работает " http://www.codeguru.com/forum/showthread.php?t=452337
"Подключение порта к указанному Сетевая карта? " http://www.codeguru.com/forum/showthread.php?t=451117 . В этом потоке упоминается Функция CreateIpForwardEntry (), которая (Я думаю) может быть использован для создания запись в таблице маршрутизации, чтобы все исходящий IP-трафик с указанным сервер маршрутизируется через указанный адаптер.
«Работа с 2 платами Ethernet» на http://www.codeguru.com/forum/showthread.php?t=448863
"Странная привязка к многосетевому система "на http://www.codeguru.com/forum/showthread.php?t=452368
Надеюсь, что это поможет!
-121--2162181-Для любого языка рекомендуется сначала написать код, который можно читать и обслуживать, а затем при необходимости оптимизировать.
Если ваша программа работает достаточно быстро, разделяясь на простые в переваривании фрагменты, оставьте ее путь. Если он бежит медленно, то, как упомянуто о хободаве, профиль, чтобы найти причину медлительности.
Скорее всего, это будет вызвано чем-то, кроме вызова функций, но если это вызвано, тогда начать объединение функций вместе,как только вы отследили это до этого.
http://www.slideshare.net/madrobby/extreme-javascript-performance слайды 10..19
10 000 вызовов имеют значение для IE и Firefox. 1 звонок - нет.
Лучший способ узнать, как "дорогостоящие вызовы функций", совершенно расплывчатая и контекстно-специфическая метрика, - профилировать ее самостоятельно: