Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Win32 Subclassing with CVF

pcurtis
Beginner
721 Views
I need to subclass a window in a different process. Evidently, the way to do this is to inject my DLL via a hook into the target process' address space. For this to work, my DLL needs to be able to pass a few data values (the hook and target window handles) between the source and target process' address spaces.

There is a fair amount of chat (MSDN, Richter, etc.) on how to do this in C, which apparently allows linker directives to be imbedded directly into the source code to create a named data segment for any variable, which can then be given the "/section:myseg,RWS" link attribute, so data in that segment will be identically available (shared) among all process instances of the DLL.

Can this be done in F90? I cannot find any means within DevStudio to name data segments and set their sharing attributes, and the CVF documentation doesn't address this issue. Alternatively, if anyone can provide a working example of DLL injection which solves this problem in some other way, that would be greatly appreciated.

TIA,
Paul Curtis, pcurtis@kiltel.com
0 Kudos
6 Replies
Steven_L_Intel1
Employee
721 Views
I know you can specify /section by just typing it in on the Link settings page. I don't know offhand how you would create your own section.

Steve
0 Kudos
gfthomas8
Novice
721 Views
I've only read about this dll injection business but I have no direct experience in doing it.

Search for /SECTION in the VC++ docs to find out how to set the attributes of a section, including 'sharing' with the target process(es).
0 Kudos
Jugoslav_Dujic
Valued Contributor II
721 Views
I know about global hooking technique only in general; I've never used it myself. Perhaps the attached file could help establish a global memory segment (via MapViewOfFile). Disclaimer: I didn't use it and I forgot where I downloaded it from (probably www.fortranlib.com). On a quick glance, you should create your own DllEntryPoint:
[/pre]
INTEGER FUNCTION DllEntryPoint(hModule, fdwReason, lpvReserved)
!DEC$ATTRIBUTES STDCALL:: DllEntryPoint
USE DFWIN

IMPLICIT NONE

INTEGER:: hModule, fdwReason, lpvReserved

SELECT CASE (fdwReason)
CASE(DLL_PROCESS_ATTACH)
DllEntryPoint=1
CASE DEFAULT
DllEntryPoint=1
END SELECT

END FUNCTION DllEntryPoint[/pre]
On DLL_PROCESS_ATTACH, try to OpenShareBuffer, and if it fails CreateShareBuffer. Use cray pointers to read from *bufferAddress. Of course, bufferAddress must be global to DllEntryPoint and hook routine.
HTH
Jugoslav

0 Kudos
pcurtis
Beginner
721 Views
Thanks for the replies. However... DLL injection is evidently too complicated and I needed a quick fix, so I dropped back & punted.

The original goal was to subclass the other (child) process, launched from my main thread, to trap SC_MINIMIZE messages and prevent its being minimized (my app gets rid of the taskbar, start button, etc.). The other process is typically Notepad, Excel or Paint.

Here is a poor-man's method of doing the same thing; it works fine, but lacks elegance:


TYPE(T_WINDOWPLACEMENT) :: wp
INTEGER :: rval

IF (IsWindow(hwnd_ChildProcess) /= 0) THEN
wp%length = SIZEOF(wp)
rval = GetWindowPlacement (hwnd_ChildProcess, wp)
IF (wp%showCmd == SW_SHOWMINIMIZED) THEN
wp%showCmd = SW_SHOWNORMAL
rval = SetWindowPlacement (hwnd_ChildProcess, wp)
CALL SetFocus (hwnd_ChildProcess)
END IF
END IF
0 Kudos
gfthomas8
Novice
721 Views
Now I see what you were doing. You don't need to subclass for this. If I want the character map, say, to be always available and not minimized I do:

integer id !global

...
! poll Windows for the app; if it's not running, start it, and if it is, restore it

use ... !whatever api mods required
type(T_STARTUPINFO) StartInfo
type(T_PROCESS_INFORMATION) ProcessInfo
integer r
...
If (FindWindow(NULL, "Unicode Character Map") /= 0) then
StartInfo%wShowWindow = SW_NORMAL
StartInfo%cb = len(StartInfo)
r = CreateProcess(NULL, "charmap.exe"C, 0, 0, 0, 0, CREATE_SEPARATE_WOW_VDM, NULL, StartInfo, ProcessInfo)
Sleep(500)
id = ProcessInfo%hProcess
r = CloseHandle(ProcessInfo%hThread)
Else
r = ShowWindow(FindWindow(NULL, "Unicode Character Map"), SW_RESTORE)
End If

...
!Do cleanup
integer r
use ... !whatever api mods required
If id > 0 Then
r = TerminateProcess(id, 0)
r = CloseHandle(id)
End If

The user is free to minimize or close the app and you respond by opening it up again. In the case of Excel, etc. they could loose data but the app will let them know and they'll soon get the message.

This is similar to what you've been doing. I don't consider it inelegant.
0 Kudos
Jugoslav_Dujic
Valued Contributor II
721 Views
Maybe changing Excel's window styles (remove WS_MINIMIZEBUTTON & WS_THICKFRAME, add possibly WS_DLGFRAME) could be a more ellegant solution?
0 Kudos
Reply