I'm not quite sure what i might be doing wrong but i keep getting System.ArgumentException
when i look at the IDL(generated by ITyteLib Veiwer) I can see both struct and modules
typedef struct tagXxxStruct {
short type;
short file;
short rec;
short word;
short start_bit;
short length;
short flags;
short padding;
short value;
short padV[3];
short status;
short padA[3];
} XxxStruct;
[entry("dat"), helpstring("...")]
short _stdcall dat_Int(
[in] LPSTR Server,
[in] short num_points,
[in, out] SAFEARRAY(XxxStruct)* XxxStruct_data);
I when use DllImport like so:
[DllImport("hscnetapi.dll", EntryPoint = "dat", CallingConvention = CallingConvention.StdCall)]
public static extern unsafe short dat_SA([MarshalAs(UnmanagedType.LPStr)] string host, short num_points, [MarshalAs(UnmanagedType.SafeArray)] XxxStruct[] dat_data);
And call it like so
public struct XxxStruct
{
public short type;
public short file;
public short rec;
public short word;
public short start_bit;
public short Length;
public short Flags;
public short padding;
public short value;
public short[] padV;
public short Status;
public short[] padA;
}
server = "localhost";
XxxStruct[] xobj= new XxxStruct[2];
for (i = 0; i <= 1; i++)
{
var _with1 = xobj[i];
_with1.type = 2;
_with1.file = 8;
_with1.rec = 1;
_with1.word = ((short)(359 + (i)));
_with1.Flags = 0;
_with1.padV = new short[3];
_with1.padA = new short[3];
xobj[i] = _with1;
}
dat_SA(server, (short)2, xobj);
You need to add a MarshalAs attribute to the padV and padA arrays. And quite possibly a StructLayout attribute.
[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct XxxStruct
{
public short type;
public short file;
public short rec;
public short word;
public short start_bit;
public short Length;
public short Flags;
public short padding;
public short value;
[MarshalAs(UnmanagedType.LPArray, SizeConst=3)]
public short[] padV;
public short Status;
[MarshalAs(UnmanagedType.LPArray, SizeConst=3)]
public short[] padA;
}
Related
I see that Microsoft.Windows.EventTracing.Interop.Metadata.NativeTraceLogfileHeader contains a value for BootTime. That could be useful in some cases. Any chance that will be exposed via the ITraceMetaData interface or can that be somehow else accessed?
// Microsoft.Windows.EventTracing.Metadata.ITraceMetadata
using Microsoft.Windows.EventTracing;
public interface ITraceMetadata
{
Version OSVersion
bool Is32Bit
FrequencyValue ProcessorSpeed
TraceClockType ClockType
FrequencyValue PerformanceCounterFrequency
TraceTimestampValue? ReferenceTimestampValue
FrequencyValue ProcessorUsageTimerFrequency
TraceTimestamp FirstAnalyzerDisplayedEventTime
TraceTimestamp LastEventTime
TraceDuration AnalyzerDisplayedDuration
long LostBufferCount
long LostEventCount
string TracePath
DateTimeOffset StartTime
DateTimeOffset StopTime
int ProcessorCount
int KernelEventVersion
}
Update
I have added the suggested code of dmatsion to ETWAnalyzer.
Now you can do
ETWAnalyzer -dump stats
I'll let a current team member answer regarding what changes can be made. Conceptually, before the v1 API shipped, I think it would have made sense to add this data to ITraceMetadata.
I don't recall adding this data to anything else in the API. (I checked ISystemMetadata and didn't see it there.) The only workaround I'm aware of would be to use IEventConsumer/IFilteredEventConsumer to parse the payload of the event containing this data (always the first event in the trace, I think, with whatever ProviderId/Id that event has; I don't recall off-hand).
If I recall correctly, the payload is just the TRACE_LOGFILE_HEADER structure.
But note that there are both 32-bit and 64-bit versions of that event due to the LoggerName/LogFileName pointers in it (based on the bitness of the trace, not the bitness of the machine processing the trace).
EDIT:
Here's a sample exe that gets the boot time via the trace header event. (I'm using trace.Use(), but IFilteredEventConsumer would be equivalent.)
using Microsoft.Windows.EventTracing;
using System;
using System.Runtime.InteropServices;
class Program
{
static int Main(string[] args)
{
if (args.Length != 1)
{
Console.Error.WriteLine("Usage: GetTraceBootTime.exe <trace.etl>");
return 1;
}
string tracePath = args[0];
using (ITraceProcessor trace = TraceProcessor.Create(tracePath))
{
DateTime? bootTime = null;
Guid eventTraceProviderId = new Guid("68fdd900-4a3e-11d1-84f4-0000f80464e3");
trace.Use(new[] { eventTraceProviderId }, e =>
{
if (e.Event.Id != 0 || e.Event.Version != 2)
{
return;
}
var data = e.Event.Data;
long rawBootTime;
if (e.Event.Is32Bit)
{
if (data.Length < Marshal.SizeOf<NativeTraceHeaderEvent32>())
{
throw new InvalidOperationException("Invalid 32-bit trace header event.");
}
// FYI - Inefficient / lots of copies, but doesn't require compiling with /unsafe.
IntPtr pointer = Marshal.AllocHGlobal(data.Length);
Marshal.Copy(data.ToArray(), 0, pointer, data.Length);
NativeTraceHeaderEvent32 typedData = Marshal.PtrToStructure<NativeTraceHeaderEvent32>(pointer);
Marshal.FreeHGlobal(pointer);
rawBootTime = typedData.BootTime;
}
else
{
if (data.Length < Marshal.SizeOf<NativeTraceHeaderEvent64>())
{
throw new InvalidOperationException("Invalid 64-bit trace header event.");
}
// FYI - Inefficient / lots of copies, but doesn't require compiling with /unsafe.
IntPtr pointer = Marshal.AllocHGlobal(data.Length);
Marshal.Copy(data.ToArray(), 0, pointer, data.Length);
NativeTraceHeaderEvent64 typedData = Marshal.PtrToStructure<NativeTraceHeaderEvent64>(pointer);
Marshal.FreeHGlobal(pointer);
rawBootTime = typedData.BootTime;
}
// See https://learn.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-trace_logfile_header:
// BootTime is ticks since midnight, January 1, 1601 and is apparently UTC (despite documentation to the
// contrary).
DateTime epoch = new DateTime(1601, 1, 1, 0, 0, 0, DateTimeKind.Utc);
bootTime = epoch.AddTicks(rawBootTime);
e.Cancel();
});
trace.Process();
Console.WriteLine(bootTime);
}
return 0;
}
// https://learn.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-trace_logfile_header
[StructLayout(LayoutKind.Sequential)]
struct NativeTraceHeaderEvent64
{
public uint BufferSize;
public byte MajorVersion;
public byte MinorVersion;
public byte SubVersion;
public byte SubMinorVersion;
public uint ProviderVersion;
public uint NumberOfProcessors;
public long EndTime;
public uint TimerResolution;
public uint MaximumFileSize;
public uint LogFileMode;
public uint BuffersWritten;
public uint StartBuffers;
public uint PointerSize;
public uint EventsLost;
public uint CpuSpeedInMHz;
public ulong LoggerName;
public ulong LogFileName;
public NativeTimeZoneInformation TimeZone;
public long BootTime;
public long PerfFreq;
public long StartTime;
public uint ReservedFlags;
public uint BuffersLost;
}
// https://learn.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-trace_logfile_header
[StructLayout(LayoutKind.Sequential)]
struct NativeTraceHeaderEvent32
{
public uint BufferSize;
public byte MajorVersion;
public byte MinorVersion;
public byte SubVersion;
public byte SubMinorVersion;
public uint ProviderVersion;
public uint NumberOfProcessors;
public long EndTime;
public uint TimerResolution;
public uint MaximumFileSize;
public uint LogFileMode;
public uint BuffersWritten;
public uint StartBuffers;
public uint PointerSize;
public uint EventsLost;
public uint CpuSpeedInMHz;
public uint LoggerName;
public uint LogFileName;
public NativeTimeZoneInformation TimeZone;
public long BootTime;
public long PerfFreq;
public long StartTime;
public uint ReservedFlags;
public uint BuffersLost;
}
// https://learn.microsoft.com/en-us/windows/win32/api/timezoneapi/ns-timezoneapi-time_zone_information
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct NativeTimeZoneInformation
{
public int Bias;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public char[] StandardName;
public NativeSystemTime StandardDate;
public int StandardBias;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public char[] DaylightName;
public NativeSystemTime DaylightDate;
public int DaylightBias;
}
// https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-systemtime
[StructLayout(LayoutKind.Sequential)]
struct NativeSystemTime
{
public short wYear;
public short wMonth;
public short wDayOfWeek;
public short wDay;
public short wHour;
public short wMinute;
public short wSecond;
public short wMilliseconds;
}
}
I have developed a simple Console application to poll an Xbox Controller using xinput. I would like to use the values obtained from one of the thumbsticks to move the mouse. I am able to get the x and y values from the thumbstick, but when I use those values to SendInput() (using the User32.dll), the mouse does not move and the return value is 0.
According to Microsoft, "If the function returns zero, the input was already blocked by another thread."
How do I find the other thread that is blocking it? It is just a simple Console Application (exe) started by Visual Studio that prints the x and y values to the screen and attempts to move the mouse.
long x = controller.x; // values from the controller
long y = controller.y; // these are checked and do contain numbers
INPUT mouseMoveInput = new INPUT();
mouseMoveInput.type = 0; // mouse
mouseMoveInput.mi.dx = x;
mouseMoveInput.mi.dy = y;
mouseMoveInput.mi.mouseData = 0;
mouseMoveInput.mi.dwFlags = MOUSEEVENTF_MOVE;
var result = SendInput(1, ref mouseMoveInput, Marshal.SizeOf(new INPUT());
// result always returns 0
Am I missing something? Should this work?
Here are declarations:
[StructLayout(LayoutKind.Explicit)]
public struct MOUSEINPUT
{
[FieldOffset(0)]
public long X;
[FieldOffset(8)]
public long Y;
[FieldOffset(16)]
public uint MouseData;
[FieldOffset(20)]
public uint Flags;
[FieldOffset(24)]
public uint Time;
[FieldOffset(28)]
public IntPtr ExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
internal struct KEYBOARDINPUT
{
public ushort Vk;
public ushort Scan;
public uint Flags;
public uint Time;
public IntPtr ExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
internal struct HARDWAREINPUT
{
public uint Msg;
public ushort ParamL;
public ushort ParamH;
}
[StructLayout(LayoutKind.Explicit)]
public struct INPUT
{
[FieldOffset(0)]
public uint type;
[FieldOffset(4)]
public MOUSEINPUT mi;
[FieldOffset(4)]
public KEYBOARDINPUT ki;
[FieldOffset(4)]
public HARDWAREINPUT hi;
}
UPDATE: using mouse-event does work, but this function is deprecated. Is there a problem with using it anyway since it works?
There is something odd I'm getting with the struct sizes:
Size of tagINPUT: 40
Size of mouseMoveInput: 40
Size of MOUSEINPUT: 32
Size of uint: 4
But if tagINPUT consists of MOUSEINPUT and uint then shouldn't it's size be 36?
The 2nd parameter of SendInput should be a pointer to an array, not a ref parameter, and especially not a ref directly to the struct.
I would also use explicit layout only for the struct that actually needs it, and let the rest be sequential. It's easier.
This code works for me:
const int INPUT_MOUSE = 0;
const int MOUSEEVENTF_MOVE = 0x0001;
[DllImport("user32.dll", SetLastError = true)]
private static extern uint SendInput(uint numberOfInputs, [MarshalAs(UnmanagedType.LPArray)] INPUT[] inputs, int sizeOfInputStructure);
void Main()
{
INPUT mouseMoveInput = new INPUT();
mouseMoveInput.type = INPUT_MOUSE;
mouseMoveInput.mi.dx = 10;
mouseMoveInput.mi.dy = 10;
mouseMoveInput.mi.mouseData = 0;
mouseMoveInput.mi.dwFlags = MOUSEEVENTF_MOVE;
var result = SendInput(1, new INPUT[] { mouseMoveInput}, Marshal.SizeOf(mouseMoveInput));
if(result == 0) {
throw new Win32Exception();
}
}
[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
public int dx;
public int dy;
public uint mouseData;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct HARDWAREINPUT
{
public uint Msg;
public ushort ParamL;
public ushort ParamH;
}
[StructLayout(LayoutKind.Explicit)]
public struct INPUT
{
[FieldOffset(0)]
public uint type;
[FieldOffset(4)]
public MOUSEINPUT mi;
[FieldOffset(4)]
public KEYBDINPUT ki;
[FieldOffset(4)]
public HARDWAREINPUT hi;
}
I am running a c# application that makes use of the sendinputs method in windows to mimic keystrokes. It works fine when I am remoted into the instance, but as soon as I log out it throws an exception. Can anyone offer any thoughts on why this is happening, and how to avoid it?
UPDATE::
here is some sample code that can reproduce the issue.
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ConsoleApplication6
{
class Program
{
class SendKey
{
[StructLayout(LayoutKind.Sequential)]
private struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public int dwFlags;
public int time;
public int dwExtraInfo;
};
[StructLayout(LayoutKind.Sequential)]
private struct KEYBDINPUT
{
public short wVk;
public short wScan;
public int dwFlags;
public int time;
public int dwExtraInfo;
};
[StructLayout(LayoutKind.Sequential)]
private struct HARDWAREINPUT
{
public int uMsg;
public short wParamL;
public short wParamH;
};
[StructLayout(LayoutKind.Explicit)]
private struct INPUT
{
[FieldOffset(0)]
public int type;
[FieldOffset(4)]
public MOUSEINPUT no;
[FieldOffset(4)]
public KEYBDINPUT ki;
[FieldOffset(4)]
public HARDWAREINPUT hi;
};
[DllImport("user32.dll")]
private extern static void SendInput(int nInputs, ref INPUT pInputs, int cbsize);
[DllImport("user32.dll", EntryPoint = "MapVirtualKeyA")]
private extern static int MapVirtualKey(int wCode, int wMapType);
private const int INPUT_KEYBOARD = 1;
private const int KEYEVENTF_KEYDOWN = 0x0;
private const int KEYEVENTF_KEYUP = 0x2;
private const int KEYEVENTF_EXTENDEDKEY = 0x1;
private void Send(Keys key, bool isEXTEND)
{
INPUT inp = new INPUT();
inp.type = INPUT_KEYBOARD;
inp.ki.wVk = (short)key;
inp.ki.wScan = (short)MapVirtualKey(inp.ki.wVk, 0);
inp.ki.dwFlags = ((isEXTEND) ? (KEYEVENTF_EXTENDEDKEY) : 0x0) | KEYEVENTF_KEYDOWN;
inp.ki.time = 0;
inp.ki.dwExtraInfo = 0;
SendInput(1, ref inp, Marshal.SizeOf(inp));
System.Threading.Thread.Sleep(100);
inp.ki.dwFlags = ((isEXTEND) ? (KEYEVENTF_EXTENDEDKEY) : 0x0) | KEYEVENTF_KEYUP;
SendInput(1, ref inp, Marshal.SizeOf(inp));
}
static void Main()
{
while(true)
{
System.Threading.Thread.Sleep(2000);
SendKey s = new SendKey();
s.Send(Keys.Z, false);
s.Send(Keys.Left, true);
}
}
}
}
}
if you build this and just run it on a free windows server ec2 instance with notepad in focus it will print zzzzzz continuously while you are remoted into the instance, however, as soon as you remote out of the instance, it will stop printing until you log back in.
I'm trying to marshal the MIB_TCPTABLE_OWNER_MODULE struct from a P/Invoked' call into GetExtendedTcpTable, defined in iphlpapi.dll.
My P/Invoke signature is defined as this:
[DllImport("iphlpapi.dll", SetLastError = true)]
private static extern uint GetExtendedTcpTable(IntPtr pTcpTable, ref int dwSize, bool sort, int ipVersion, int tableClass, int reserved);
According to the documentation on MSDN (and looking through the header files), this should set the pTcpTable parameter to the address of a MIB_TCPTABLE_OWNER_MODULE structure, who has a member which is an array of MIB_TCPROW_OWNER_MODULE structures. From tcpmib.h:
typedef struct _MIB_TCPTABLE_OWNER_MODULE
{
DWORD dwNumEntries;
MIB_TCPROW_OWNER_MODULE table[ANY_SIZE];
} MIB_TCPTABLE_OWNER_MODULE, *PMIB_TCPTABLE_OWNER_MODULE;
ANY_SIZE is defined to be 1.
Here is my problem; I've defined the MIB_TCPTABLE_OWNER_MODULE and MIB_TCPROW_OWNER_MODULE structs in C# like so:
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct MIB_TCPTABLE_OWNER_MODULE
{
public uint dwNumEntries;
MIB_TCPROW_OWNER_MODULE table;
}
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct MIB_TCPROW_OWNER_MODULE
{
public uint dwState;
public uint dwLocalAddr;
public uint dwLocalPort;
public uint dwRemoteAddr;
public uint dwRemotePort;
public uint dwOwningPid;
public ulong liCreateTimestamp;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TCPIP_OWNING_MODULE_SIZE)]
public ulong[] OwningModuleInfo;
}
Since I won't know the size of the returned MIB_TCPTABLE_OWNER_MODULE's table member at declaration, my plan was to increment the IntPtr and use Marshal.PtrToStructure to extract each array member from the table member.
The call to Marshal.PtrToStructure returns (no memory violation exceptions), but I wind up with garbage values in the struct members. Here is my complete code:
[DllImport("iphlpapi.dll", SetLastError = true)]
private static extern uint GetExtendedTcpTable(IntPtr pTcpTable, ref int dwSize, bool sort, int ipVersion, int tableClass, int reserved);
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct MIB_TCPROW_OWNER_MODULE
{
public uint dwState;
public uint dwLocalAddr;
public uint dwLocalPort;
public uint dwRemoteAddr;
public uint dwRemotePort;
public uint dwOwningPid;
public ulong liCreateTimestamp;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TCPIP_OWNING_MODULE_SIZE)]
public ulong[] OwningModuleInfo;
}
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct MIB_TCPTABLE_OWNER_MODULE
{
public uint dwNumEntries;
MIB_TCPROW_OWNER_MODULE table;
}
private const int TCPIP_OWNING_MODULE_SIZE = 16;
private const int AF_INET = 2;
private const int TCP_TABLE_OWNER_MODULE_ALL = 8;
public static void GetConnectionDetails()
{
var bufferSize = 0;
var ret = GetExtendedTcpTable(IntPtr.Zero, ref bufferSize, true, AF_INET, TCP_TABLE_OWNER_MODULE_ALL, 0);
var tableBuffer = Marshal.AllocHGlobal(bufferSize);
try
{
ret = GetExtendedTcpTable(tableBuffer, ref bufferSize, true, AF_INET, TCP_TABLE_OWNER_MODULE_ALL, 0);
if (ret != 0)
throw new Exception("Oh noes!");
var convertedTable = (MIB_TCPTABLE_OWNER_MODULE)Marshal.PtrToStructure(tableBuffer, typeof (MIB_TCPTABLE_OWNER_MODULE));
var finalTable = new MIB_TCPROW_OWNER_MODULE[convertedTable.dwNumEntries];
var rowPtr = (IntPtr) ((long) tableBuffer + Marshal.SizeOf(convertedTable.dwNumEntries));
for (int i = 0; i < convertedTable.dwNumEntries; i++)
{
var row = (MIB_TCPROW_OWNER_MODULE)Marshal.PtrToStructure(rowPtr, typeof (MIB_TCPROW_OWNER_MODULE));
finalTable[i] = row;
rowPtr = (IntPtr) ((long) rowPtr + Marshal.SizeOf(row)); // Move to the next entry
}
foreach (var entry in finalTable)
{
// do something with each entry
Console.WriteLine(entry.dwState);
Console.WriteLine(entry.dwRemoteAddr);
}
}
finally
{
Marshal.FreeHGlobal(tableBuffer);
}
}
Comparing memory between this and an unmanaged version (that works properly), I do see some differences in the memory of the marshaled struct that I can't account for; there are a few bytes different.
Any assistance is most appreciated!
Consider this struct:
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct MIB_TCPTABLE_OWNER_MODULE
{
public uint dwNumEntries;
MIB_TCPROW_OWNER_MODULE table;
}
You are assuming that the offset of table is equal to the size of dwNumEntries. But you are forgetting about alignment. Since the largest type in MIB_TCPROW_OWNER_MODULE is 8 bytes wide, that type has alignment of 8. Which means that in order for it to be aligned it must be placed at an offset that is a multiple of 8. And hence there is padding between dwNumEntries and table. You need to allow for that padding.
So, at this point:
var rowPtr = (IntPtr) ((long) tableBuffer +
Marshal.SizeOf(convertedTable.dwNumEntries));
you add 4 to the address held in tableBuffer. You actually need to add 8. You should use Marshal.OffsetOf to calculate the offset:
var rowPtr = (IntPtr)((long)tableBuffer +
(long)Marshal.OffsetOf(typeof(MIB_TCPTABLE_OWNER_MODULE), "table"));
Is there an equivalent to SendInput for WPF? I've looked into AutomationPeer classes but was not successfull.
I simply want to send a Keydown (the Enter Key). Simply raising the event (RaiseEvent) does not work in my scenario.
Here is what I have, which is working. I'd prefer to have a managed code alternative.
private void comboSelectionChanged(object sender, SelectionChangedEventArgs args)
{
((ComboBox)sender).Focus();
// send keydown
INPUT input = new INPUT();
input.type = INPUT_KEYBOARD;
input.union.keyboardInput.wVk = 0x0D;
input.union.keyboardInput.time = 0;
SendInput(1, ref input, Marshal.SizeOf(input));
}
[DllImport("user32.dll", SetLastError = true)]
private static extern int SendInput(int nInputs, ref INPUT mi, int cbSize);
[StructLayout(LayoutKind.Sequential)]
private struct INPUT
{
public int type;
public INPUTUNION union;
};
[StructLayout(LayoutKind.Explicit)]
private struct INPUTUNION
{
[FieldOffset(0)]
public MOUSEINPUT mouseInput;
[FieldOffset(0)]
public KEYBDINPUT keyboardInput;
};
[StructLayout(LayoutKind.Sequential)]
private struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public int dwFlags;
public int time;
public IntPtr dwExtraInfo;
};
[StructLayout(LayoutKind.Sequential)]
private struct KEYBDINPUT
{
public short wVk;
public short wScan;
public int dwFlags;
public int time;
public IntPtr dwExtraInfo;
};
private const int INPUT_MOUSE = 0;
private const int INPUT_KEYBOARD = 1;
You can emulate a keystroke like this:
public void SendKey(UIElement sourceElement, Key keyToSend)
{
KeyEventArgs args = new KeyEventArgs(InputManager.Current.PrimaryKeyboardDevice, PresentationSource.FromVisual(sourceElement), 0, keyToSend);
args.RoutedEvent = Keyboard.KeyDownEvent;
InputManager.Current.ProcessInput(args);
}
You could then call it like this:
SendKey(myComboBox, Key.Enter);
I suppose you can put this in a static class somewhere, or even make an extension method out of it. However, I would argue that in most cases there is a more elegant way to accomplish this.
I hope this helps.