Results 1 to 14 of 14

Thread: EditStreamCallback() and outside apps

  1. #1

    Thread Starter
    Addicted Member
    Join Date
    May 2006
    Location
    Ithaca, NY
    Posts
    145

    EditStreamCallback() and outside apps

    I have seen plenty of VB6 examples of EditStreamCallback using EM_STREAMIN/OUT. Here's one from this site:

    http://vbforums.com/showthread.php?t=336077

    However, I've yet to see one for .NET anywhere and I really need help setting it up. If I could get some help I would greatly appreciate it, please use Notepad as the example external app.

    I just need to get text and set text in a form on an external app and WM_GET/SETTEXT don't work because it's a Rich Text form... I am already familiar with basic API functions like FindWindow, SendMessage, and PostMessage, but I'm clueless when it comes to EditStreamCallback... Please start from square one if possible.

  2. #2
    Frenzied Member
    Join Date
    Jul 2005
    Posts
    1,168

    Re: EditStreamCallback() and outside apps

    Try this:

    VB Code:
    1. Const EM_STREAMOUT = 1098
    2.     Const SF_RTF = 2
    3.  
    4.  
    5.     Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByRef es As EditStream) As Integer
    6.     Public Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByRef es As EditStream) As Integer
    7.  
    8.     Public Structure EditStream
    9.         Public dwCookie As Integer
    10.         Public dwError As Integer
    11.         Public lpEditStreamCallBack As EditStreamCallBackType
    12.     End Structure
    13.  
    14.     Public Delegate Function EditStreamCallBackType(ByVal dwCookie As Integer, ByVal buffer As String, ByVal numBytes As Integer, ByVal lpCb As Integer) As Integer
    15.  
    16.     Public Function myEditStreamCallBack(ByVal dwCookie As Integer, ByVal buffer As String, ByVal numBytes As Integer, ByVal lpCb As Integer) As Integer
    17.         'your code here
    18.         'when thread goes through here, do what you want with the data, such as the buffer
    19.     End Function
    20.  
    21.     Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    22.         Dim es As EditStream
    23.         es = New EditStream
    24.         es.dwCookie = 0
    25.         es.dwError = 0
    26.         es.lpEditStreamCallBack = AddressOf myEditStreamCallBack
    27.         Dim ret As Integer
    28.         ret = SendMessage(RichTextBox1.Handle.ToInt32, EM_STREAMOUT, SF_RTF, es)
    29.     End Sub
    Last edited by benmartin101; Jan 25th, 2007 at 07:27 PM.

  3. #3

    Thread Starter
    Addicted Member
    Join Date
    May 2006
    Location
    Ithaca, NY
    Posts
    145

    Re: EditStreamCallback() and outside apps

    Thanks for the help but...

    What exactly is this code doing? can you comment it a little bit please? If you feel like it, would you put an example of using this like for getting/sending text to and from wordpad or something?

  4. #4
    Frenzied Member
    Join Date
    Jul 2005
    Posts
    1,168

    Re: EditStreamCallback() and outside apps

    You could copy the code to a new vb.net project. Add a richtextbox control, named RichTextBox1. So after the SendMessage() is called, if you place a breakpoint within myEditStreamCallBack(), then check the value of the parameter "buffer", you'll see that its the data in the richtextbox.

  5. #5

    Thread Starter
    Addicted Member
    Join Date
    May 2006
    Location
    Ithaca, NY
    Posts
    145

    Re: EditStreamCallback() and outside apps

    I really appreciate the help but I just don't really understand all of this you know?

    When my program executes the SendMessage function and uses the editstream, it never executes the code within myEditStreamCallback... I can't even get a message box to pop up... What could the problem be?

    And could you please go more in depth to this? I really don't understand any of this callback function and I would like to for future use. Please make an example that shows you using the edit stream to grab what is written in an outside app's rich text box(wordpad for ex)... I would also like to see how to set the text in that rtb from my program as well.

  6. #6

    Thread Starter
    Addicted Member
    Join Date
    May 2006
    Location
    Ithaca, NY
    Posts
    145

    Re: EditStreamCallback() and outside apps

    Another problem I'm having is when I send the EM_STREAMOUT message to a rich text form, it always crashes the program I'm sending it to.

  7. #7
    Frenzied Member
    Join Date
    Jul 2005
    Posts
    1,168

    Re: EditStreamCallback() and outside apps

    A callback function, to my understanding, is basically an application-defined function. When you run an application, it has its own EditStreamCallBack function, which it calls everytime EM_STREAMOUT or EM_STREAMIN is sent. What we are trying to do is make it call our own "custom" EditStreamCallBack function. So instead of it going to its usual callback function, it goes to ours, which in turn, allows us to do stuff with its parameters; whether to use them or change them. That's why in my previous post when I said to put a breakpoint in the "custom" EditStreamCallBack function, it will stop there during debug because its now using that function as its callback.

    However, my previous post will not work with external(outside) apps. To do it with external apps, you will need to "inject" code into the app. To be more precise, you will need to inject the "custom" callback function code. The reason for this is because when you send EM_STREAMOUT or EM_STREAMIN to the external application, it will look for the function it its OWN (the external app's) process memory. Remember the EditStream structure? Its properties include the pointer (or memory address) to the "custom" callback function, but that function only exist in your main application's process memory, not in the external app. When the external app looks into that memory location(within its own process memory), it crashes because the "custom" function does not exist there. So anyways, here is the code for the dll, which needs to be done using C++.

    Continued on the next post...

  8. #8
    Frenzied Member
    Join Date
    Jul 2005
    Posts
    1,168

    Re: EditStreamCallback() and outside apps

    Code:
    #include "stdafx.h"
    
    #pragma data_seg(".shared")
    char sharedStr[255] = "a";
    char sharedRichTextBoxString[255] = "a";
    	int addr = 0;
    	HMODULE module = 0;
    	int flag = 0;
    #pragma data_seg()
    #pragma comment(linker, "/SECTION:.shared,RWS")
    
    
    BOOL APIENTRY DllMain( HANDLE hModule, 
                           DWORD  ul_reason_for_call, 
                           LPVOID lpReserved
    					 )
    {
    	if(flag==0) 
    	{
    		module = GetModuleHandle("C:\\Program Files\\Microsoft Visual Studio\\MyProjects\\EditStreamCallBack\\Debug\\EditStreamCallBack.dll");
    		addr = (int)GetProcAddress(module, (LPCSTR)"EditStreamCallBack");
    		flag = 1;
    	}
        return TRUE;
    }
    
    __declspec(dllexport) void _stdcall SetText(char * str)
    {
    	int sz = strlen(str);
    	memcpy(sharedStr, str, sz);
    	
    }
    
    __declspec(dllexport) HMODULE _stdcall GetModuleH()
    {
    	return module;
    }
    
    __declspec(dllexport) int _stdcall GetAddr() 
    {
    	return addr;
    }
    
    
    __declspec(dllexport) char * _stdcall GetRichTextBoxString()
    {
    	return sharedRichTextBoxString;
    }
    
    
    __declspec(dllexport) int CALLBACK EditStreamCallBack(DWORD dwCookie, LPBYTE buf, DWORD numByte, DWORD* cb)
    {
    	if(dwCookie==1) //if 1, then we want it to work for EM_STREAMIN
    	{
    		memcpy(buf, sharedStr, strlen(sharedStr));
    		*cb = strlen(sharedStr);
    	}
    	else if(dwCookie==2) //if 2, then we want it to work for EM_STREAMOUT
    	{
    		memcpy(sharedRichTextBoxString, buf, numByte);
    	}
    	return 0;
    }
    When you've compiled that to a .DLL, here's the .NET code for the main application
    VB Code:
    1. Const EM_STREAMOUT = 1098
    2.     Const SF_RTF = 2
    3.     Const SF_TEXT = 1
    4.     Const EM_STREAMIN = 1097
    5.     Const SF_UNICODE = 16
    6.     Const SFF_PLAINRTF = &H4000
    7.     Const MEM_COMMIT = &H1000
    8.     Const PAGE_READWRITE = &H4
    9.     Public Const PROCESS_ALL_ACCESS As Integer = &H1F0FFF
    10.     Public Const PROCESS_VM_WRITE As Integer = &H20
    11.     Const INFINITE = &HFFFFFFFF
    12.  
    13.     Public Declare Function WaitForSingleObject Lib "kernel32" Alias "WaitForSingleObject" (ByVal hHandle As Integer, ByVal dwMilliseconds As Integer) As Integer
    14.     Public Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Integer, ByRef lpdwProcessId As Integer) As Integer
    15.     Public Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As IntPtr, ByVal lpBaseAddress As Integer, ByRef lpBuffer As Byte, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer) As Integer
    16.     Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Integer, ByVal lpBaseAddress As Integer, ByVal lpBuffer As String, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer) As Integer
    17.     Declare Function WriteProcessMemory_EditStream Lib "kernel32" Alias "WriteProcessMemory" (ByVal hProcess As Integer, ByVal lpBaseAddress As Integer, ByRef lpBuffer As EditStream, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer) As Integer
    18.     Public Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Integer, ByVal bInheritHandle As Integer, ByVal dwProcessId As Integer) As Integer
    19.     Public Declare Function VirtualAllocEx Lib "kernel32" Alias "VirtualAllocEx" (ByVal hproc As Integer, ByVal lpAddress As Integer, ByVal dwSize As Integer, ByVal flAllocationType As Integer, ByVal flProtect As Integer) As Integer
    20.     Public Declare Function CreateRemoteThread Lib "kernel32" Alias "CreateRemoteThread" (ByVal hProcess As Integer, ByVal lpThreadAttributes As Integer, ByVal dwStackSize As Integer, ByVal lpStartAddress As Integer, ByVal lpParameter As Integer, ByVal dwCreationFlags As Integer, ByVal lpThreadId As Integer) As Integer
    21.     Public Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As Integer
    22.     Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal filename As String) As Integer
    23.     Declare Function GetProcAddress Lib "kernel32" Alias "GetProcAddress" (ByVal hmod As Integer, ByVal funcName As String) As Integer
    24.     'change dll path wherever you put the DLL file
    25.     Declare Sub SetText Lib "C:\Program Files\Microsoft Visual Studio\MyProjects\EditStreamCallBack\Debug\EditStreamCallBack.dll" (ByVal str As String)
    26.     Declare Function GetAddr Lib "C:\Program Files\Microsoft Visual Studio\MyProjects\EditStreamCallBack\Debug\EditStreamCallBack.dll" () As Integer
    27.     Declare Function GetRichTextBoxString Lib "C:\Program Files\Microsoft Visual Studio\MyProjects\EditStreamCallBack\Debug\EditStreamCallBack.dll" () As String
    28.     Declare Function GetModuleH Lib "C:\Program Files\Microsoft Visual Studio\MyProjects\EditStreamCallBack\Debug\EditStreamCallBack.dll" () As Integer
    29.     Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lpEditStream As Integer) As Integer
    30.     Public Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByRef es As EditStream) As Integer
    31.     Public Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByVal dest As IntPtr, ByVal source As String, ByVal length As Integer)
    32.  
    33.     Dim hwnd As Integer = &H3B04E2  'handle of the richedit textbox
    34.     Dim hproc As Integer
    35.     Dim esAddr As Integer
    36.  
    37.     Public Structure EditStream
    38.         Public dwCookie As Integer
    39.         Public dwError As Integer
    40.         Public lpEditStreamCallBack As Integer
    41.     End Structure
    42.  
    43.     Public Delegate Function EditStreamCallBackType(ByVal dwCookie As Integer, ByVal buffer As IntPtr, ByVal numBytes As Integer, ByVal cb As IntPtr) As Integer
    44.  
    45.     'injects dll code into (external)target process
    46.     Private Sub InjectCode()
    47.         Dim pid As Integer
    48.  
    49.         'path to EditStreamCallBack.dll - may vary depending on where you put your dll
    50.         Dim path As String = "C:\Program Files\Microsoft Visual Studio\MyProjects\EditStreamCallBack\Debug\EditStreamCallBack.dll"
    51.  
    52.         GetWindowThreadProcessId(hwnd, pid)
    53.         hproc = OpenProcess(PROCESS_ALL_ACCESS, 0, pid)
    54.         Dim remoteAddr As Integer = VirtualAllocEx(hproc, 0, Len(path), MEM_COMMIT, PAGE_READWRITE)
    55.         Dim ret As Integer = WriteProcessMemory(hproc, remoteAddr, path, Len(path), 0)
    56.         Dim hmod As Integer = GetModuleHandle("kernel32")
    57.         Dim address = GetProcAddress(hmod, "LoadLibraryA")
    58.         Dim ret2 As Integer = CreateRemoteThread(hproc, 0, 0, address, remoteAddr, 0, 0)
    59.  
    60.         WaitForSingleObject(ret2, INFINITE)
    61.     End Sub
    62.  
    63.     Private Sub Setup()
    64.         Dim es As EditStream
    65.  
    66.         InjectCode()
    67.  
    68.         'we are getting the address of the dll function "EditStreamCallBack"
    69.         Dim extAddress As Integer = GetAddr
    70.  
    71.         'string we want to write into richtextbox, which includes the RTF keycodes.
    72.         'As a final result, it should display "Cplusplus work" in the richtextbox if it works correctly
    73.         SetText("{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fswiss\fcharset0 Arial;}}{\colortbl ;\red128\green0\blue0;}{\*\generator Msftedit 5.41.21.2506;}\viewkind4\uc1\pard\cf1\f0\fs20 Cplusplus work\cf0\par}")
    74.  
    75.         es = New EditStream
    76.         es.dwCookie = 1 'use 1 if sending EM_STREAMIN or 2 if sending EM_STREAMOUT; reason: thats how our callback function is set up
    77.         es.dwError = 0
    78.         es.lpEditStreamCallBack = extAddress
    79.  
    80.         'allocate memory for EditStream structure in (external)target process
    81.         esAddr = VirtualAllocEx(hproc, 0, Marshal.SizeOf(es), MEM_COMMIT, PAGE_READWRITE)
    82.  
    83.         'write EditStream structure into (external)target process
    84.         'reason: When sending EM_STREAMIN to an external app, the external app looks for the EditStream object in its own process.
    85.         Dim res As Integer = WriteProcessMemory_EditStream(hproc, esAddr, es, Marshal.SizeOf(es), 0)
    86.     End Sub
    87.  
    88.     Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
    89.         Setup()
    90.     End Sub
    91.  
    92.  
    93.     Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    94.         'send EM_STREAMIN
    95.         SendMessage(hwnd, EM_STREAMIN, SF_RTF, esAddr)
    96.     End Sub
    97.  
    98.     Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
    99.         'send EM_STREAMOUT
    100.         SendMessage(hwnd, EM_STREAMOUT, SF_RTF, esAddr)
    101.         Dim val As String = GetRichTextBoxString() 'gets the RTF string, which includes the RTF keycodes, in the richtextbox
    102.     End Sub
    103. End Class

    You will want to first call Setup() which basically injects the DLL containing the "custom" EditStreamCallBack function. Why does it have to be in a DLL? Not really sure about the specific reason, but it has to be in these cases. If you want to learn about the inject() function, go to msdn and read about what those functions, that were used, are doing. Then either call SendMessage(...EM_STREAMOUT) or SendMessage(...EM_STREAMIN). Note: You have to change dwCookie (of EditStream structure) depending on which message your sending.
    Last edited by benmartin101; Jan 29th, 2007 at 04:48 PM.

  9. #9

    Thread Starter
    Addicted Member
    Join Date
    May 2006
    Location
    Ithaca, NY
    Posts
    145

    Re: EditStreamCallback() and outside apps

    Ok thanks. This will take some testing to see if it works for what I'm doing but it looks good.

    Is there a way to package that .dll directly in the .exe rather than having two files?

  10. #10
    Frenzied Member
    Join Date
    Jul 2005
    Posts
    1,168

    Re: EditStreamCallback() and outside apps

    I don't think there is a way to package the dll into the exe. At least none that i know of.

  11. #11
    Addicted Member
    Join Date
    Dec 2005
    Posts
    230

    Re: EditStreamCallback() and outside apps

    i just wonder if you guys have an example of VB6 instead of VB.NET. In the C++ dll code, is there anyway to change the absolute path of the dll.

    Thanks guys

  12. #12
    Frenzied Member
    Join Date
    Jul 2005
    Posts
    1,168

    Re: EditStreamCallback() and outside apps

    For the dll, yeah...you could change it. You should change the path to wherever the dll is located, or it won't work. For converting to VB6, it should be pretty straightforward. Some changes are needed. For the declarations of the dll functions that are being imported, just change all INTEGER types to LONG. I think the declaration for STRUCTURE in vb6 is a little different, but i'm gonna assume you know how to do structures in vb6. For the code Marshal.SizeOf(), you could use vb6's Len(). Also in vb6, this code is not allowed:

    dim x as integer = 1

    should be:

    dim x as integer
    x = 1

    Regarding the DELEGATE code, that is not even needed in this whole project so just take it out. So converting it to vb6 shouldn't be so hard. Just make sure that those dll function declarations have the exact same BYVAL or BYREF keyword as in mine.

  13. #13
    Addicted Member
    Join Date
    Dec 2005
    Posts
    230

    Re: EditStreamCallback() and outside apps

    Did anybody try it yet ? i try it and it just hang the external app. so bad

  14. #14
    Frenzied Member
    Join Date
    Jul 2005
    Posts
    1,168

    Re: EditStreamCallback() and outside apps

    could you post your codes? Including the declarations of the dll functions.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width