How to Create a global WH_GETMESSAGE HOOK without DLL - dll

I am trying to create a global WH_GETMESSAGE HOOK without DLL,but I can't success.
My OS is Win7 32Bit,This is my some code:
SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,GetModuleHandle(NULL),0);
Please help me if you have any time. :)

As documented,
hMod [in]
Type: HINSTANCE
A handle to the DLL containing the hook procedure pointed to by the lpfn parameter. The hMod parameter must be set to NULL if the dwThreadId parameter specifies a thread created by the current process and if the hook procedure is within the code associated with the current process.
hMod must be a handle to a DLL. Not an EXE. This is because the DLL will be loaded into all running processes to be hooked, and its code run straight from within those processes.

You need a message loop in the calling thread of SetWindowsHookEx
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

It's obvious, the last parameter shouldn't be '0', it should be the thread id of the thread you want to call the function in. You can't pass in null for both the last and next to last parameters. Use GetThreadId() to get the id of the current thread, that's most likely what you want to do.
The previous poster's answer was very useful for you, if you would have read it you would have seen the above yourself.

Related

VB.NET Interfacing with external DLL to obtain USB names from function

I am trying to interface with a USB device that provides an external C++ dll file and have read a myriad of articles surrounding delegates, marshalling, pointers and I generally get the idea of what is happening. Unfortunately, my practical experience in this area is letting me down in obtaining the final solution.
I have connected to the device in order to create a session successfully but there is a function called EnumDevices which supposedly enumerates the device list for specific future calls. The function has a function within itself that lists the devices and it is this part I am struggling with.
The enumdevices call in the API looks like this:
EnumDevices(INTERFACE,FoundDevice,NULL);
bool __stdcall FoundDevice(long data, const char *DeviceName)
{
printf("device name %s\n", DeviceName)
Return True
}
and according to the documentation, FoundDevice is a call back method called for each found device.
In VB.Net, what I have done is as follows:
Created a delegate function
Delegate Function FoundDeviceDelegate(data as integer, DeviceName as PInvoker.Marshal.ByteArrayPtr) as Boolean
Then I created a local function with the same signature
Private Function FoundDevice(data as integer, DeviceName as PInvoker.Marshal.ByteArrayPtr) as Boolean
Msgbox(DeviceName.ToString)
Return True
End Function
In my main code, I make the following declarations and calls
dim devhandler as assembly.FoundDeviceHandler = AddressOf FoundDevice
dim device as new assembly.FoundDevice(devhandler)
assembly.EnumDevices(INTERFACE,device,vbNull)
('assembly' is the reference to the external dll, 'INTERFACE' is a constant and 'device' expects a function with the two parameters - user and devicename)
I thought that the EnumDevices call would then pass back to the device reference which in turns calls the DeviceHandler which references the delegated function which would then output the device name.
What I have got is a pointer value on 'device' but I am struggling referencing this back to a device name. It is never executing the FoundDevice function to show the messagebox.
I have read so much that I think I have read too much surrounding delegates and marshalling etc that I am now struggling to get to the end which feels so close given that I have the pointer reference when I debug it.
If anyone can make sense of the above and provide any useful assistance, it would be very much appreciated.

Trying to call a C DLL from VB. Can't get one of the parameters working

Trying to set up a USB power strip.
Here's the documentation:
Initializes the Power USB API.
Name: InitPowerUSB
Parameters: model:returns the model number(1:basic, 2:digIO, 3:watchdog, 4:Smart), firmware: returns firmware version in ?.? format in a character string (major revision and minor revision)
Return: >0 if successful. Returns number of PowerUSB devices connected
C++ Example:
if (!m_pwrUSBInit)
{
int model; char firmware[8];
if ((ret=InitPowerUSB(&model, firmware)) > 0)
{
m_pwrUSBInit = 1;
m_numDevices = ret;
}
}
I have been trying to get this working with my VB6 code for around an hour now with no luck. The program either crashes, displays an error like Bad Calling Dll Convention, type mismatch, et cetera.
Here's what I have:
Public Declare Function InitPowerUSB Lib "PwrUSBDll.dll" (ByRef model As Integer, ByVal firmware As String) As Integer
Dim model As Integer
model = 0
Dim firmware As String
firmware = ""
If (InitPowerUSB(model, firmware)) > 0) Then
EndIf
I have tried changing firmware to byte arrays, byref, string, integer, long, etc. It just doesn't seem to want to run.
Does anyone know of a solution to this problem? Thanks
I can't answer the rest of your function signature woes since I don't have any documentation for your PwrUSBDll.dll.
However "Bad DLL calling convention" errors generally mean you have a CDecl entrypoint and VB6 can only call those with some help.
There are a couple of fixes.
The obvious one is to modifiy the source and recompile that DLL using StdCall instead.
Another is to create a type library for that DLL, which helps inform VB6 about the issue and resolves it.
Then you have the option of using VB6's undocumented CDecl decorator:
Public Declare Function InitPowerUSB CDecl Lib "PwrUSBDll.dll" ( _
ByRef model As Integer, _
ByVal firmware As String) As Integer
However the downside is that this will not work when run within the IDE, nor will it work when compiled to p-code. The p-code interpreter doesn't process this keyword.
So you could just bypass it in IDE runs and supply dummy results for testing, or you can create a small wrapper DLL in VB6 that you separately compile to native code.
Caveats:
For this to solve your problem we'd have to assume you are passing correct data types in that argument list. A C++ int is a VB6 Long. You are probably better off passing a VB6 Byte array ByRef for that char[8] unless this is a Unicode DLL entrypoint. The function return value is also most likely Long.

Is this a UI-threading issue? Is there an easy way to fix it?

I am communicating with a USB-HID device. It will successfully complete hundreds of send-receive requests but occasionally get a Null Exception error.
Is this a threading issue?
FormMain.vb:
myHidDevice.transmitPacket(Packet)
myHidDevice.resetEvent.WaitOne(6)
If myHidDevice.rxDataReady = True then
' Life is good
MyHidDevicePort.vb
Public Sub DataReceivedHandler(ByVal sender as Object, dataReceived as DataReceivedEventArgs)
if dataReceived.data Is Nothing Then
Exit Sub
Else
Dim rDataPacket As List(Of Byte) = dataReceived.data.ToList()
For Each element in rDataPacket
rxData.dataPacket(i) = element
rxDataReady = True
resetEvent.Set()
MySensorClass.vb
Public Overrides Function processPacket(ByRef rxStruct as rStruct, ByVal txPacket()) as Boolean
....
Select Case rxStruct.dataPacket(4)
Case MOD_DISPLAY_SET_BRIGHTNESS
rxData(0) = rxStruct.dataPacket(5)
...
at the rxData.dataPacket(i) = element I will get a NullReference error every now and then. I could enclose it in a try/catch statement, but I'd like to fix the root problem if possible.
This device is communicating to microcontrollers, and it is possible that they won't always give a value... but my feeling is this is some sort of UI threading issue. When debugging, even though there is a null exception, many times there actually does seem to be data in dataReceived.data.ToList(). Is there an easy way to place the whole data processing routine on a thread separate from the UI?
Edit: Changed code to match answer and give more info on where it is used. Still get NullReferenceExceptions after about 1,000 completed send/receive requests to the HID device.
The dialog in the comments is too restricting, so I'll try this as an answer. Unfortunately, there still isn't enough code to give a full answer.
Some sample unknowns:
What is rxData (a custome class, part of the SDK, a struct)?
Where does i come from in the code sample rxData.dataPacket(i) = element, I don't see it decalred or incremented.
Why is the form waiting on myHidDevice.resetEvent.WaitOne(6) and what does it do once it thinks there is sucess?
How/when does processPacket get called?
What I can recommend in general is that access to shared state be wrapped in a SyncLock. And in your case, that includes both rxData and rxDataReady.
In your threaded event callback you need this:
SyncLock(syncRoot)
For Each element in rDataPacket
rxData.dataPacket(i) = element
next
rxDataReady = True
resetEvent.Set()
End SyncLock
And in your Main form where you are waiting for a response you need to wrap access to the ready flag as well:
SyncLock(myHidDevice.syncRoot)
If myHidDevice.rxDataReady = True then
' do something that consumes the data read in the thread
End If
End SyncLock
You have to watch for how long you hold the lock in the read and the write because you cannot be doing both at the same time.
Over all, I wouldn't be surprised if your code code be refactored a bit to make the thread issues easier to deal with. A blocking queue / colletion as you suggested might be a good idea. Just not enough is known of you design/code to give any more concrete advice.
If you know that there is a possibility that your object may be null, placing it inside of a try-catch block would be the incorrect way of handling this situation, as that would be considered coding by exception. Instead, do a null check on your object prior to setting it. e.g.
If Not dataReceived.data Is Nothing Then
Dim rDataPacket As List(Of Byte) = dataReceived.data.ToList()
End If
If your problem lyes with the individual array elements being null, you should also check them to ensure they exist before setting/accessing them.

Tracking down the source of E_POINTER in IMFMediaSource::ReadSample

I'm getting an E_POINTER error from the ReadSample call, and as far as I can tell, none of the pointers are invalid. See snippet below (note, it's a C++/CLI app):
IMFSample* sample = NULL;
pin_ptr<IMFSample*> pinnedSample = &sample;
LONGLONG timeStamp;
HRESULT hr = mSourceReader->ReadSample(
(DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
0,
NULL,
NULL,
&timeStamp,
pinnedSample
);
I suspect the problem lies in the construction of the mSourceReader (an IMFSourceReader instance, created from an IMFMediaSource). But, alas, I've no idea how to backtrack and find the source, as all the COM calls in the chain of commands that created mSourceReader returned S_OK.
Much thanks for any tips.
You don't need pin_ptr when taking the address of a local variable, since the garbage collector never moves local variables around anyway.
I'd guess that one of the other three parameters you're passing NULL to is non-optional, but I need to see what function you're calling to know for sure.
Did you create the IMFSourceReader in synchronous or asynchronous mode? The docs say:
This method can complete synchronously or asynchronously. If you provide a callback pointer when you create the source reader, the method is asynchronous. Otherwise, the method is synchronous.
I think this is your problem:
In synchronous mode:
The pdwStreamFlags and ppSample parameters cannot be NULL. Otherwise, the method returns E_POINTER.
You've passed NULL for pdwStreamFlags, which is not allowed.
Doc link: http://msdn.microsoft.com/en-us/library/dd374665.aspx

VB.NET - Calling Kernel32.DLL's Wow64DisableWow64FsRedirection

Looking at Microsoft's page on Wow64DisableWow64FsRedirection, I see some C code. What if you want to call this function and it's revert from VB.net?
So far I have done this:
<Runtime.InteropServices.DllImport("KERNEL32.DLL", EntryPoint:="Wow64DisableWow64FsRedirection")> _
Public Shared Function DisableWow64Redirection() As Boolean
End Function
And I do likewise for the Revert brother function.
I call it like so:
DisableWow64Redirection()
This seems to work, as the shell command I call after actually finds its exe in system32, but I am not sure about the Revert, does it need a parameter? This Revert page seems to want me to take the output from disable and plug it into the revert call. Does that sound right? How do I change my DLLimport to take in a boolean and actually use it in the Kernal32.DLL function?
Thanks!
You could change your function definition to
<DllImport("kernel32.dll", EntryPoint := "Wow64DisableWow64FsRedirection")> _
Public Shared Function DisableWow64Redirection(ByRef output As IntPtr) As Boolean
and define Revert() like so:
<DllImport("kernel32.dll", EntryPoint := "Wow64RevertWow64FsRedirection")> _
Public Shared Function RevertWow64Redirection(ByRef handle As IntPtr) As Boolean
You'd invoke these like so:
Dim handle As IntPtr
DisableWow64Redirection(handle)
RevertWow64Redirection(handle)
I'm not a VB.NET guy, so maybe some syntax is incorrect - the important thing is that you provide a reference parameter of IntPtr type, which maps to the PVOID native type. You'll want to hang on to it, and pass the same value to Revert().
The declaration is wrong, it takes a (ByRef oldValue As IntPtr) argument. Which you need to pass to the revert function.
However, you cannot safely use this in a .NET program. It also affects the CLR, it won't be able to find .NET framework assemblies anymore. You cannot predict when they get loaded. There are surely better ways to accomplish what you need, start a new question about that.