블로그 이미지
Every unexpected event is a path to learning for you.

카테고리

분류 전체보기 (2737)
Unity3D (817)
Programming (474)
Python (8)
TinyXML (5)
STL (13)
D3D (3)
MFC (1)
C/C++ (54)
C++/CLI (45)
C# (250)
WinForm (6)
WPF (5)
Math (10)
A.I. (1)
Win32API (11)
Algorithm (3)
Design Pattern (7)
UML (1)
MaxScript (1)
FMOD (4)
FX Studio (1)
Lua (2)
Terrain (1)
Shader (3)
boost (2)
Xml (2)
JSON (4)
Etc (11)
Monad (1)
Html5 (4)
Qt (1)
Houdini (0)
Regex (10)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (228)
협업 (58)
3DS Max (3)
Game (12)
Utility (136)
Etc (96)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (53)
Android (14)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (18)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday
04-25 00:00

GetWindowRect함수는 화면상의 특정 Window에 대한 위치및 크기를 반환하는 함수입니다.

Declare Function GetWindowRect Lib "user32" Alias "GetWindowRect" (ByVal hwnd As Integer, ByRef lpRect As RECT) As Integer
▶VB.NET 선언

[DllImport("user32")]
public static extern int GetWindowRect(int hwnd, ref RECT lpRect);
▶C# 선언

선언 GetWindowRect함수의 첫번째 인수는 위치및 크기를 얻고자 하는 Window의 Handle을 지정하고 두번째 인수에 실제 위치와 크기에 대한 값이 저장될 구조체를 지정합니다.

여기서 사용되는 구조체는 다음과 같이 선언됩니다.

Public Structure RECT
Public left As Integer
Public top As Integer
Public right As Integer
Public bottom As Integer
End Structure
▶VB.NET

public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
▶C#

만일 실행중인 현재 Form에 대한 위치및 크기값을 가져오려면 GetWindowRect함수를 다음과 같이 선언합니다.

Dim stRect As RECT
GetWindowRect(Me.Handle, stRect)

▶VB.NET 호출

RECT stRect = default(RECT);
GetWindowRect((int)this.Handle, ref stRect);

▶C# 호출



출처 :  http://lab.cliel.com/m/post/view/id/39

반응형
Posted by blueasa
, |

IT, C#, FolderBrowserDialog, C# FolderBrowserDialog, C# 디렉토리, C# OpenFileDialog, OpenFileDialog




How to C# selecting a Directory in an open file dialog
http://ssscripting.wordpress.com/2009/06/07/c-selecting-a-directory-in-an-open-file-dialog/

FolderBrowserDialog dialog = new FolderBrowserDialog();
dialog.SelectedPath  = @"C:\";    // 열 때 폴더를 지정하려면 이런식으로..(추가)

dialog.ShowDialog();
string selected = dialog.SelectedPath;

이렇게 코딩하면 폴더 찾아보기를 구현할 수 있고 선택한 정보는 dialog.SelectedPath 로 넘어오게 되어 폴더 경로 정보를 처리할 수 있습니다.


출처 : http://ndolson.com/1370



[추가] 

폴더 다이얼로그 열릴 때, 시작되는 폴더 위치를 알고싶어서 찾다가

ShowDialog 하기 전에 SelectedPath를 셋팅해주면 된다는 걸 알고 글에 추가해놓음..

근데..

화면 이상 내려가면 스크롤을 내려야 보이는데..

포커스 있는 지점으로 스크롤 이동은 안될려나..

좀 더 알아봐야 될 듯..

반응형
Posted by blueasa
, |

[DllImport("user32.dll")]

static extern IntPtr GetDC(IntPtr hWnd);


[DllImport("user32.dll")]

static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);


[DllImport("gdi32.dll")]

static extern int GetPixel(IntPtr hDC, int x, int y);


//GetPixel()함수 정의, Color객체 반환

static public Color GetPixel(Control control, int x, int y)

{

Color color = Color.Empty;

if (control != null)

{

IntPtr hDC = GetDC(control.Handle);

int colorRef = GetPixel(hDC, x, y);

color = Color.FromArgb(

  (int)(colorRef & 0x000000FF),

  (int)(colorRef & 0x0000FF00) >> 8,

  (int)(colorRef & 0x00FF0000) >> 16);

ReleaseDC(control.Handle, hDC);

}

return color;

}




반응형
Posted by blueasa
, |

using System;
using
System.Collections.Generic;
using
System.ComponentModel;
using
System.Data;
using
System.Drawing;
using
System.Linq;
using
System.Text;
using
System.Windows.Forms;
using
System.Runtime.InteropServices;
using
System.Text.RegularExpressions;


namespace
Color_tool
{
public partial class Form1 : Form
{
   
Regex rgbInputR;
   
Regex rgbInputG;
   
Regex rgbInputB;

   
Match R, G, B;
   
int r;
   
int g;
   
int b;


   
string colorX;

   
[DllImport("gdi32")]
   
private static extern int GetPixel(IntPtr hdc, int x, int y);
   
[DllImport("User32")]
   
private static extern IntPtr GetWindowDC(IntPtr hwnd);

   
private static readonly IntPtr DesktopDC = GetWindowDC(IntPtr.Zero);

   
public static System.Drawing.Color GetPixelAtCursor()
   
{
       
System.Drawing.Point p = Cursor.Position;
       
return System.Drawing.Color.FromArgb(GetPixel(DesktopDC, p.X, p.Y));
   
}

   
public Form1()
   
{
       
InitializeComponent();
   
}

   
private void Form1_Load(object sender, EventArgs e)
   
{
        button1
.BackColor = Color.Black;
   
}

   
private void timer1_Tick(object sender, EventArgs e)
   
{
        colorX
= GetPixelAtCursor().ToString();
       
Color backX = GetPixelAtCursor();
       
this.BackColor = Color.FromArgb(r,g,b);
        label1
.Text = colorX;
        RGB_value
();
   
}

   
private void button1_Click(object sender, EventArgs e)
   
{
       
if (timer1.Enabled == false)
            timer1
.Enabled = true;
       
else
            timer1
.Enabled = false;
   
}

   
private void RGB_value()
   
{
        rgbInputR
= new Regex(@"(?<=R=)\d{0,3}");
        rgbInputG
= new Regex(@"(?<=G=)\d{0,3}");
        rgbInputB
= new Regex(@"(?<=B=)\d{0,3}");

       
Match R, G, B;

        R
= rgbInputR.Match(colorX);
        G
= rgbInputG.Match(colorX);
        B
= rgbInputB.Match(colorX);
       
//had to flip the R and B ???
        b
= int.Parse(R.Groups[0].Value);
        g
= int.Parse(G.Groups[0].Value);
        r
= int.Parse(B.Groups[0].Value);
   
}
 
}
}





반응형
Posted by blueasa
, |

mouse_event (user32)

Programming/C# / 2012. 5. 21. 17:12

Summary
The mouse_event API

C# Signature:

[DllImport("user32.dll")]
static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData,
   UIntPtr dwExtraInfo);

or

[DllImport("user32.dll")]
static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData,
  int dwExtraInfo);

Note that for non-relative mouse movement (i.e. if MOUSEEVENTF_ABSOLUTE is not specified as part of dwFlags), negative values for dx and dy are desirable. As such, the "uint" type specification for C# can be safely replaced with Int32.

User-Defined Types:

  [Flags]
  public enum MouseEventFlags : uint
  {
    LEFTDOWN   = 0x00000002,
    LEFTUP     = 0x00000004,
    MIDDLEDOWN = 0x00000020,
    MIDDLEUP   = 0x00000040,
    MOVE       = 0x00000001,
    ABSOLUTE   = 0x00008000,
    RIGHTDOWN  = 0x00000008,
    RIGHTUP    = 0x00000010,
    WHEEL      = 0x00000800,
    XDOWN      = 0x00000080,
    XUP    = 0x00000100
  }

  //Use the values of this enum for the 'dwData' parameter
  //to specify an X button when using MouseEventFlags.XDOWN or
  //MouseEventFlags.XUP for the dwFlags parameter.
  public enum MouseEventDataXButtons : uint
  {
    XBUTTON1   = 0x00000001,
    XBUTTON2   = 0x00000002
  }

VB.Net Signature:

This function does indeed return a value, just as the keybd_event API does.

If there is a real error, it will in fact return a value of false, or zero.

The dwExtraInfo appears to be a ULONG_PTR in C++ (IntPtr in VB.NET)

Declare Function apimouse_event Lib "user32.dll" Alias "mouse_event" (ByVal dwFlags As Int32, ByVal dX As Int32, ByVal dY As Int32, ByVal cButtons As Int32, ByVal dwExtraInfo As Int32) As Boolean

Notes:

FYI, Microsoft tells us for "Windows NT/2000/XP: This function has been superseded. Use SendInput instead."

The C# code below works fine. However you have to keep in mind to add the namespace "System.Runtime.InteropServices" and keep in mind to write the code into a class.

Original contributor tells us:aa

I wanted to emulate the scroll. Searching for this information wasn't easy ... but here is how you do the mouse scroll button

dim ScrollValue as Integer

ScrollValue = 120 'or -120 for up or down scrolling

mouse_event(&H800, 0, 0, ScrollValue, 0)

Tips & Tricks:

Another contributor tells us:

The scroll value can actually be any value larger than 1, if used within a loop.

This allows you to smoothly increment the scrollbar, instead of relying on the inconsistent wheel delta,

which is a variable limited by the user, for mouse wheel. Start-Control Panel-Mouse-Wheel-Scrolling

VB.NET Sample Code:

    Const MOUSEEVENTF_WHEEL As Int32 = 2048
    Const MOUSEEVENTF_WHEEL_DELTA As Int32 = 120

    Private Declare Function apimouse_event Lib "user32" Alias "mouse_event" (ByVal dwFlags As Int32, ByVal dX As Int32, ByVal dY As Int32, ByVal cButtons As Int32, ByVal dwExtraInfo As Int32) As Boolean
    Private Declare Function apiGetMessageExtraInfo Lib "user32" Alias "GetMessageExtraInfo" () As Int32

    Private Sub PlayScroll(ByVal number As Int32, Optional ByVal increment As Int32 = 2)
    On Error Resume Next
    For i As Int32 = 1 To number
        apimouse_event(MOUSEEVENTF_WHEEL, 0, 0, increment, apiGetMessageExtraInfo)
    Next
    End Sub

C# Sample Code:

    [DllImport("user32.dll")]
    static extern void mouse_event(int dwFlags, int dx, int dy, int dwData, int dwExtraInfo);

    [Flags]
    public enum MouseEventFlags
    {
        LEFTDOWN = 0x00000002,
        LEFTUP = 0x00000004,
        MIDDLEDOWN = 0x00000020,
        MIDDLEUP = 0x00000040,
        MOVE = 0x00000001,
        ABSOLUTE = 0x00008000,
        RIGHTDOWN = 0x00000008,
        RIGHTUP = 0x00000010
    }

    public static void LeftClick(int x, int y)
    {
        Cursor.Position = new System.Drawing.Point(x, y);
        mouse_event((int)(MouseEventFlags.LEFTDOWN), 0, 0, 0, 0);
        mouse_event((int)(MouseEventFlags.LEFTUP), 0, 0, 0, 0);
    }

VB.NET 2005 Sample Code:

Based on http://vb-helper.com/howto_move_click_mouse.html

This code assumes a form called frmMain with a command button called cmdClick a picture box called picClicker and a text box called txtResults

Note Twips are no more. Also, I stripped the FOR loop of delta moves from the command button click to the middle of the picture box.

Option Explicit On

Friend Class frmMain

    Inherits System.Windows.Forms.Form

    Declare Auto Sub mouse_event Lib "user32" (ByVal dwFlags As Int32, ByVal dx As Int32, ByVal dy As Int32, ByVal cButtons As Int32, ByVal dwExtraInfo As IntPtr)

    Const MOUSEEVENTF_MOVE As Int32 = &H1 '  mouse move
    Const MOUSEEVENTF_LEFTDOWN As Int32 = &H2 '  left button down
    Const MOUSEEVENTF_LEFTUP As Int32 = &H4 '  left button up
    Const MOUSEEVENTF_RIGHTDOWN As Int32 = &H8 '  right button down
    Const MOUSEEVENTF_RIGHTUP As Int32 = &H10 '  right button up
    Const MOUSEEVENTF_MIDDLEDOWN As Int32 = &H20 '  middle button down
    Const MOUSEEVENTF_MIDDLEUP As Int32 = &H40 '  middle button up
    Const MOUSEEVENTF_ABSOLUTE As Int32 = &H8000 '  absolute move
    Const MOUSEEVENTF_WHEEL As Int32 = &H800 ' wheel button rolled

    ' Simulate moving the mouse to the center of the
    ' PictureBox and clicking.
    Private Sub cmdClick_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles cmdClick.Click
    Dim cur_x As Single
    Dim cur_y As Single
    Dim dest_x As Single
    Dim dest_y As Single

    ' mouse_event moves in a coordinate system where
    ' (0, 0) is in the upper left corner and
    ' (65535,65535) is in the lower right corner.

    ' Get the current mouse coordinates and convert
    ' them into this new system.
    cur_x = System.Windows.Forms.Cursor.Position.X * 65535 / System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width
    cur_y = System.Windows.Forms.Cursor.Position.Y * 65535 / System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height

    ' Convert the coordinates of the center of the
    ' picClicker PictureBox into this new system.
    Dim pt As Point = picClicker.PointToScreen(New Point(picClicker.ClientRectangle.Width / 2, picClicker.ClientRectangle.Height / 2))

    dest_x = pt.X * 65535 / System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width
    dest_y = pt.Y * 65535 / System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height

    txtResults.Text = txtResults.Text & "From " & System.Windows.Forms.Cursor.Position.X & " " & System.Windows.Forms.Cursor.Position.Y & " to " & pt.X & " " & pt.Y & vbCrLf
    txtResults.Text = txtResults.Text & "From " & cur_x & " " & cur_y & " to " & dest_x & " " & dest_y & vbCrLf

    ' Move the mouse to its final destination and click it.
    mouse_event(MOUSEEVENTF_ABSOLUTE + MOUSEEVENTF_MOVE + MOUSEEVENTF_LEFTDOWN + MOUSEEVENTF_LEFTUP, dest_x, dest_y, 0, 0)
    End Sub

    Private Sub picClicker_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles picClicker.Click
    txtResults.Text = txtResults.Text & "MouseClick" & vbCrLf
    End Sub

    Private Sub picClicker_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles picClicker.MouseDown
    txtResults.Text = txtResults.Text & "MouseDown (" & e.X & ", " & e.Y & ")" & vbCrLf
    End Sub

    Private Sub picClicker_MouseUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles picClicker.MouseUp
    txtResults.Text = txtResults.Text & "MouseUp (" & e.X & ", " & e.Y & ")" & vbCrLf
    End Sub

End Class

Alternative Managed API:

Per http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/win32map.asp , mouse_event is supposed to be replaced by .NET Framework API System.Windows.Forms.MouseEventArgs but this is not the case. MouseEventArgs is just a data structure w/out event capability. I tried to get:

Dim eMouse As New System.Windows.Forms.MouseEventArgs(Windows.Forms.MouseButtons.Left, 1, pt.X, pt.Y, 0)

Me.OnMouseDown(eMouse)

Me.OnMouseMove(eMouse)

Me.OnMouseUp(eMouse)

to work as desired. Although it did trigger mouse events in the form showing the movement and click action desired, it didn't move the mouse pointer on the screen nor did it trigger events in the picture box located at pt.X, pt.Y

Thus I have resigned myself to unmanaged code for now. I will post the SendInput version shortly as mouse_event has been deprecated by Bill in favor ofSendInput.

As the original contributor noted:

You can use the System.Windows.Forms.Cursor.Position property to set the position of the mouse, if you would like.

You will note I have replaced the GetCursorPos calls in the original VB source with this as suggested in the MSDN URL I mention above.

Documentation
mouse_event on MSDN




반응형
Posted by blueasa
, |

keybd_event (user32)

Programming/C# / 2012. 5. 21. 11:48

KEYEVENTF_KEYUP 상수 찾다가 발견..


도움 될 것 같아서 퍼옴..



Summary
This function is useful to simulate Key presses to the window with focus.

It will return a value of false, if there is an error simulating the key press.

C# Signature:

[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags,
   UIntPtr dwExtraInfo);

or

[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags,
   int dwExtraInfo);

VB Signature:

<DllImport("user32.dll", CallingConvention:=CallingConvention.StdCall, _
           CharSet:=CharSet.Unicode, EntryPoint:="keybd_event", _
           ExactSpelling:=True, SetLastError:=True)> _
Public Shared Function keybd_event(ByVal bVk As Byte, ByVal bScan As Byte, _
                              ByVal dwFlags As Int32, ByVal dwExtraInfo As Int32) As Boolean
End Function

User-Defined Types:

None

Notes:

None.

Tips & Tricks:

This function is useful to simulate Key presses (for input use the virtual keycodes from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp or windows CE universal core virtual key code compact charthttp://msdn2.microsoft.com/en-us/library/ms927178.aspx ).

Use FindWindow and SetForegroundWindow to direct input to the desired window.

Note
WaitForInputIdle (Warning this will only wait once! See Raymond Chen's Blog Post http://blogs.msdn.com/b/oldnewthing/archive/2010/03/25/9984720.aspx ), or a Sleep may be required to assure Window is ready for input:

  RUN('NOTEPAD.EXE')
  Sleep(2000,0)
  SetForegroundWindow (FindWindow('Untitled - Notepad'))

(see also VkKeyScan):

    void PressKey( byte keyCode )
    {
        const int KEYEVENTF_EXTENDEDKEY = 0x1;
        const int KEYEVENTF_KEYUP       = 0x2;
        keybd_event( keyCode, 0x45, KEYEVENTF_EXTENDEDKEY, 0 );
        keybd_event( keyCode, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0 );
    }

Sample Code:

VB Sample:

This sample will generate a 'Scroll Lock' key press event when the user clicks 'Button1'.

  • Create a new Windows Application project;
  • Drop a button control in the recently created form;
  • Add the following code to the form class:

Imports System.Runtime.InteropServices

Public Class Form1

    <DllImport("user32.dll", CallingConvention:=CallingConvention.StdCall, _
           CharSet:=CharSet.Unicode, EntryPoint:="keybd_event", _
           ExactSpelling:=True, SetLastError:=True)> _
    Public Shared Sub keybd_event(ByVal bVk As Byte, ByVal bScan As Byte, _
                                  ByVal dwFlags As Integer, ByVal dwExtraInfo As Integer) As Boolean
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Const VK_SCROLL As Byte = &H91
        Const KEYEVENTF_KEYUP As Byte = &H2

        keybd_event(VK_SCROLL, 0, 0, 0)               ' Generates a KEY_DOWN
        keybd_event(VK_SCROLL, 0, KEYEVENTF_KEYUP, 0) ' Generates a KEY_UP

    End Sub

End Class

Please add some more!

Alternative Managed API: System.Windows.Forms.SendKeys

Documentation
keybd_event on MSDN

PROBLEM: How do i use combination of shift and tab keys at the same time ?

Answer:posted by dokks http://www.ravensmyst.com

define the shift key as a const

    public const byte VK_LSHIFT= 0xA0; // left shift key
    public const byte VK_TAB = 0x09;
    public const int KEYEVENTF_EXTENDEDKEY = 0x01;
    public const int KEYEVENTF_KEYUP = 0x02;

    //press the shift key
    keybd_event(VK_LSHIFT, 0x45, 0, 0);

    //press the tab key
    keybd_event(VK_TAB, 0x45, 0, 0);

    //release the tab key
    keybd_event(VK_TAB, 0x45, KEYEVENTF_KEYUP, 0);

    //release the shift key
    keybd_event(VK_LSHIFT, 0x45, KEYEVENTF_KEYUP, 0);

I'm using this to create automated UI testing for a custom Textbox control. After a lot of trial and error the following code worked well for me.

    public partial class Form2 : Form
    {
    [DllImport("user32.dll", SetLastError = true)]
    static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);

    Keys[] numberKeys = new Keys[10] { Keys.D0, Keys.D1, Keys.D2, Keys.D3, Keys.D4, Keys.D5, Keys.D6, Keys.D7, Keys.D8, Keys.D9 };

    void PressKey(Keys key)
    {
        const int KEYEVENTF_EXTENDEDKEY = 0x1;
        const int KEYEVENTF_KEYUP = 0x2;
        // I had some Compile errors until I Casted the final 0 to UIntPtr like this...
        keybd_event((byte)key, 0x45, KEYEVENTF_EXTENDEDKEY, (UIntPtr)0);
        keybd_event((byte)key, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, (UIntPtr)0);
    }

    void PressKeyArray(Keys[] keys)
    {
        foreach (Keys key in keys)
        {
        PressKey(key);
        }
    }

    private void Compare(object sender, string expected, string actual)
    {
        Button ClickedButton = (Button)sender;

        if (expected == actual)
        ClickedButton.Text = "Pass";
        else
        ClickedButton.Text = "Fail";
    }

    private void buttonNumericAccept_Click(object sender, EventArgs e)
    {
        string expected = "0123456789";

        NumericTextbox.AcceptNumeric = true;

        //
        // Send Appropriate Key Presses
        //
        NumericTextbox.Focus();
        PressKeyArray(numberKeys);
        Application.DoEvents();

        // Process Results        
        Compare(sender, expected, NumericTextbox.Text);        
    }
    }



출처 : http://www.pinvoke.net/default.aspx/user32.keybd_event

반응형
Posted by blueasa
, |

C# 코드

[DllImport("StoreUI_ko_Http.dll", CharSet = CharSet.Auto)]
public static extern void GetPage(string url, out string data);

 

C++ 코드

__declspec(dllexport) void GetPage(BSTR url, BSTR* Result)
 {
         char* pBuffer = NULL;

         HttpConnectGet(url, &pBuffer);
 
         CComBSTR bstrResult = UTF8ToUNICODE(pBuffer);
        *Result = bstrResult.Detach();

        free(pBuffer);
  } 

 

WinXP 환경에서는 위의 코드가 정상적으로 동작하지만

 

Vista에서는 타입변환 오류가 발생되고 만다.

 

스트링 대신에 바이트 타입으로 하면 에러는 발생되지 않지만

 

한글의 경우 유니코드 환경에서 데이타가 다 깨져버린다.

 

해결 방법은 아래처럼 string을 IntPtr로 변경해서 처리하면 된다.

 

IntPtr 는 C#처럼 포인터를 지원하지 않는 어플리케이션과 데이터를 주고 받을때

 

사용하면 편리하다.

 

IntPtr는 C++에서 넘기는 스트링에 대한 포인터 주소값을 저장하게 된다.

 

C# 코드

[DllImport("StoreUI_ko_Http.dll", CharSet = CharSet.Auto)]
 public static extern void GetPage(string url, out IntPtr data);

 

IntPtr param = IntPtr.Zero;  // 초기값 할당 

GetPage("", param);             // C++ 함수 호출

string msg = System.Runtime.InteropServices.Marshal.PtrToStringAuto(param); //string 변환

 

C++ 코드

__declspec(dllexport) void GetPage(BSTR url, BSTR* Result)
 {
         char* pBuffer = NULL;

         HttpConnectGet(url, &pBuffer);
 
         CComBSTR bstrResult = UTF8ToUNICODE(pBuffer);
        *Result = bstrResult.Detach();

        free(pBuffer);
  } 




[출처] C#과 C++ DLL 간의 스트링 데이타 교환|작성자 옆집엉아

반응형

'Programming > C#' 카테고리의 다른 글

mouse_event (user32)  (0) 2012.05.21
keybd_event (user32)  (0) 2012.05.21
C# String을 C++ char로 변환  (0) 2012.05.14
Returning Strings from a C++ API to C#  (0) 2012.05.14
SendMessage C# -> C++ with String  (0) 2012.05.09
Posted by blueasa
, |



1
2
3
4
5
6
7
8
9
10
using System.Runtime.InteropServices;
 
String strHello = "Hello";
// IntPtr나 System::String^로 넘겨 주면 됨
IntPtr pStr = Marshal.StringToHGlobalUni(strHello );
 
// pStr  사용
 
// 사용 후 메모리 해제
Marshal.FreeHGlobal(pStr);
단순한 코드라 설명을 생략



반응형
Posted by blueasa
, |

1. Introduction.

1.1 APIs that return strings are very common. However, the internal nature of such APIs, as well as the use of such APIs in managed code, require special attention. This blog will demonstrate both concerns.

1.2 I will present several techniques for returning an unmanaged string to managed code. But before that I shall first provide an in-depth explanation on the low-level activities that goes on behind the scenes. This will pave the way towards easier understanding of the codes presented later in this blog.

2. Behind the Scenes.

2.1 Let’s say we want to declare and use an API written in C++ with the following signature :

char* __stdcall StringReturnAPI01();

This API is to simply return a NULL-terminated character array (a C string).

2.2 To start with, note that a C string has no direct representation in managed code. Hence we simply cannot return a C string and expect the CLR to be able to transform it into a managed string.

2.3 The managed string is non-blittable. It can have several representations in unmanaged code : e.g. C-style strings (ANSI and Unicode-based) and BSTRs. Hence, it is important that you specify this information in the declaration of the unmanaged API, e.g. :

[DllImport("<path to DLL>", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string StringReturnAPI01();

In the above declaration, note that the following line :

[return: MarshalAs(UnmanagedType.LPStr)]

indicates that the return value from the API is to be treated as a NULL-terminated ANSI character array (i.e. a typical C-style string).

2.4 Now this unmanaged C-style string return value will then be used by the CLR to create a managed string object. This is likely achieved by using the Marshal.PtrToStringAnsi() method with the incoming string pointer treated as an IntPtr.

2.5 Now a very important concept which is part and parcel of the whole API calling operation is memory ownership. This is an important concept because it determines who is responsible for the deallocation of this memory. Now the StringReturnAPI01() API supposedly returns a string. The string should thus be considered equivalent to an “out” parameter, It is owned by the receiver of the string, i.e. the C# client code. More precisely, it is the CLR’s Interop Marshaler that is the actual receiver.

2.6 Now being the owner of the returned string, the Interop Marshaler is at liberty to free the memory associated with the string. This is precisely what will happen. When the Interop Marshaler has used the returned string to construct a managed string object, the NULL-terminated ANSI character array pointed to by the returned character pointer will be deallocated.

2.7 Hence it is very important to note the general protocol : the unmanaged code will allocate the memory for the string and the managed side will deallocate it. This is the same basic requirement of “out” parameters.

2.8 Towards this protocol, there are 2 basic ways that memory for an unmanaged string can be allocated (in unmanaged code) and then automatically deallocated by the CLR (more specifically, the interop marshaler) :

  • CoTaskMemAlloc()/Marshal.FreeCoTaskMem().
  • SysAllocString/Marshal.FreeBSTR().

Hence if the unmanaged side used CoTaskMemAlloc() to allocate the string memory, the CLR will use the Marshal.FreeCoTaskMem() method to free this memory.

The SysAllocString/Marshal.FreeBSTR() pair will only be used if the return type is specified as being a BSTR. This is not relevant to the example given in point 2.1 above. I will demonstrate a use of this pair in section 5 later.

2.9 N.B. : Note that the unmanaged side must not use the “new” keyword or the “malloc()” C function to allocate memory. The Interop Marshaler will not be able to free the memory in these situations. This is because the “new” keyword is compiler dependent and the “malloc” function is C-library dependent. CoTaskMemAlloc(), and SysAllocString() on the other hand, are Windows APIs which are standard.

Another important note is that although GlobalAlloc() is also a standard Windows API and it has a counterpart managed freeing method (i.e. Marshal.FreeHGlobal()), the Interop Marshaler will only use the Marshal.FreeCoTaskMem() method for automatic memory freeing of NULL-terminated strings allocated in unmanaged code. Hence do not use GlobalAlloc() unless you intend to free the allocated memory by hand using Marshal.FreeHGlobal() (an example of this is give in section 6 below).

3. Sample Code.

3.1 In this section, based on the principles presented in section 2, I shall present sample codes to demonstrate how to return a string from an unmanaged API and how to declare such an API in managed code.

3.2 The following is a listing of the C++ function which uses CoTaskMemAlloc() :

extern "C" __declspec(dllexport) char*  __stdcall StringReturnAPI01()
{
    char szSampleString[] = "Hello World";
    ULONG ulSize = strlen(szSampleString) + sizeof(char);
    char* pszReturn = NULL;

    pszReturn = (char*)::CoTaskMemAlloc(ulSize);
    // Copy the contents of szSampleString
    // to the memory pointed to by pszReturn.
    strcpy(pszReturn, szSampleString);
    // Return pszReturn.
    return pszReturn;
}

3.4 The C# declaration and sample call :

[DllImport("<path to DLL>", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string StringReturnAPI01();

static void CallUsingStringAsReturnValue()
{
  string strReturn01 = StringReturnAPI01();
  Console.WriteLine("Returned string : " + strReturn01);
}

3.5 Note the argument used for the MarshalAsAttribute : UnmanagedType.LPStr. This indicates to the Interop Marshaler that the return string from StringReturnAPI01() is a pointer to a NULL-terminated ANSI character array.

3.6 What happens under the covers is that the Interop Marshaler uses this pointer to construct a managed string. It likely uses the Marshal.PtrToStringAnsi() method to perform this. The Interop Marshaler will then use the Marshal.FreeCoTaskMem() method to free the character array.

4. Using a BSTR.

4.1 In this section, I shall demonstrate here how to allocate a BSTR in unmanaged code and return it in managed code together with memory deallocation.

4.2 Here is a sample C++ code listing :

extern "C" __declspec(dllexport) BSTR  __stdcall StringReturnAPI02()
{
  return ::SysAllocString((const OLECHAR*)L"Hello World");
}

4.3 And the C# declaration and usage :

[DllImport("<path to DLL>", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.BStr)]
public static extern string StringReturnAPI02();

static void CallUsingBSTRAsReturnValue()
{
  string strReturn = StringReturnAPI02();
  Console.WriteLine("Returned string : " + strReturn);
}

Note the argument used for the MarshalAsAttribute : UnmanagedType.BStr. This indicates to the Interop Marshaler that the return string from StringReturnAPI02() is a BSTR.

4.4 The Interop Marshaler then uses the returned BSTR to construct a managed string. It likely uses the Marshal.PtrToStringBSTR() method to perform this. The Interop Marshaler will then use the Marshal.FreeBSTR() method to free the BSTR.

5. Unicode Strings.

5.1 Unicode strings can be returned easily too as the following sample code will demonstrate.

5.2 Here is a sample C++ code listing :

extern "C" __declspec(dllexport) wchar_t*  __stdcall StringReturnAPI03()
{
  // Declare a sample wide character string.
  wchar_t  wszSampleString[] = L"Hello World";
  ULONG  ulSize = (wcslen(wszSampleString) * sizeof(wchar_t)) + sizeof(wchar_t);
  wchar_t* pwszReturn = NULL;

  pwszReturn = (wchar_t*)::CoTaskMemAlloc(ulSize);
  // Copy the contents of wszSampleString
  // to the memory pointed to by pwszReturn.
  wcscpy(pwszReturn, wszSampleString);
  // Return pwszReturn.
  return pwszReturn;
}

5.3 And the C# declaration and usage :

[DllImport("<path to DLL>", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.LPWStr)]
public static extern string StringReturnAPI03();

static void CallUsingWideStringAsReturnValue()
{
  string strReturn = StringReturnAPI03();
  Console.WriteLine("Returned string : " + strReturn);
}

The fact that a wide charactered string is now returned requires the use of the UnmanagedType.LPWStr argument for the MarshalAsAttribute.

5.4 The Interop Marshaler uses the returned wide-charactered string to construct a managed string. It likely uses the Marshal.PtrToStringUni() method to perform this. The Interop Marshaler will then use the Marshal.FreeCoTaskMem() method to free the wide-charactered string.

6. Low-Level Handling Sample 1.

6.1 In this section, I shall present some code that will hopefully cement the reader’s understanding of the low-level activities that had been explained in section 2 above.

6.2 Instead of using the Interop Marshaler to perform the marshaling and automatic memory deallocation, I shall demonstrate how this can be done by hand in managed code.

6.3 I shall use a new API which resembles the StringReturnAPI01() API which returns a NULL-terminated ANSI character array :

extern "C" __declspec(dllexport) char*  __stdcall PtrReturnAPI01()
{
  char   szSampleString[] = "Hello World";
  ULONG  ulSize = strlen(szSampleString) + sizeof(char);
  char*  pszReturn = NULL;

  pszReturn = (char*)::GlobalAlloc(GMEM_FIXED, ulSize);
  // Copy the contents of szSampleString
  // to the memory pointed to by pszReturn.
  strcpy(pszReturn, szSampleString);
  // Return pszReturn.
  return pszReturn;
}

6.4 And the C# declaration :

[DllImport("<path to DLL>", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr PtrReturnAPI01();

Note that this time, I have indicated that the return value is an IntPtr. There is no [return : ...] declaration and so no unmarshaling will be performed by the Interop Marshaler.

6.5 And the C# low-level call :

static void CallUsingLowLevelStringManagement()
{
  // Receive the pointer to ANSI character array
  // from API.
  IntPtr pStr = PtrReturnAPI01();
  // Construct a string from the pointer.
  string str = Marshal.PtrToStringAnsi(pStr);
  // Free the memory pointed to by the pointer.
  Marshal.FreeHGlobal(pStr);
  pStr = IntPtr.Zero;
  // Display the string.
  Console.WriteLine("Returned string : " + str);
}

This code demonstrates an emulation of the Interop Marshaler in unmarshaling a NULL-terminated ANSI string. The returned pointer from PtrReturnAPI01() is used to construct a managed string. The pointer is then freed. The managed string remains intact with a copy of the returned string.

The only difference between this code and the actual one by the Interop Marshaler is that the GlobalAlloc()/Marshal.FreeHGlobal() pair is used. The Interop Marshaler always uses Marshal.FreeCoTaskMem() and expects the unmanaged code to use ::CoTaskMemAlloc().

7. Low-Level Handling Sample 2.

7.1 In this final section, I shall present one more low-level string handling technique similar to the one presented in section 6 above.

7.2 Again we do not use the Interop Marshaler to perform the marshaling and memory deallocation. Additionally, we will also not release the memory of the returned string.

7.3 I shall use a new API which simply returns a NULL-terminated Unicode character array which has been allocated in a global unmanaged memory :

wchar_t gwszSampleString[] = L"Global Hello World";

extern "C" __declspec(dllexport) wchar_t*  __stdcall PtrReturnAPI02()
{
  return gwszSampleString;
}

This API returns a pointer to the pre-allocated global Unicode string “gwszSampleString”. Because it is allocated in global memory and may be shared by various functions in the DLL, it is crucial that it is not deleted.

7.4 The C# declaration for PtrReturnAPI02() is listed below :

[DllImport("<path to DLL>", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr PtrReturnAPI02();

Again, there is no declaration for interop marshaling (no use of the [return : ...] declaration). The returned IntPtr is returned as is.

7.5 And a sample C# code to manage the returned IntPtr :

static void CallUsingLowLevelStringManagement02()
{
  // Receive the pointer to Unicde character array
  // from API.
  IntPtr pStr = PtrReturnAPI02();
  // Construct a string from the pointer.
  string str = Marshal.PtrToStringUni(pStr);
  // Display the string.
  Console.WriteLine("Returned string : " + str);
}

Here, the returned IntPtr is used to construct a managed string from an unmanaged NULL-terminated Unicode string. The memory of the unmanaged Unicode string is then left alone and is not deleted.

Note that because a mere IntPtr is returned, there is no way to know whether the returned string is ANSI or Unicode. In fact, there is no way to know whether the IntPtr actually points to a NULL-terminated string at all. This knowledge has to be known in advance.

7.6 Furthermore, the returned IntPtr must not point to some temporary string location (e.g. one allocated on the stack). If this was so, the temporary string may be deleted once the API returns. The following is an example :

extern "C" __declspec(dllexport) char* __stdcall PtrReturnAPI03()
{
  char szSampleString[] = "Hello World";
  return szSampleString;
}

By the time this API returns, the string contained in “szSampleString” may be completely wiped out or be filled with random data. The random data may not contain any NULL character until many bytes later. A crash may ensue a C# call like the following :

IntPtr pStr = PtrReturnAPI03();
// Construct a string from the pointer.
string str = Marshal.PtrToStringAnsi(pStr);




반응형
Posted by blueasa
, |

[서론]

  이전에 W.O.W 접속유지 프로그램을 만든적은 있지만 그때는 WOW 캡션이 정해져 있었고, 키입력만으로(방향키를 사용했음) 접속유지가 됐기때문에 단순한 키입력 메시지 전달만 하면 끝이었다. 

  다만.. W.O.W 에서 SendMessage를 먹어버려서 PostMessage로 처리했었다.

  (W.O.W 접속유지 프로그램 링크:http://blueasa.tistory.com/527)


  이번에는 서로(현재는 C# -> C++ 만 되는거 보고 정리함.. 나중에 업뎃 할지도..) SendMessage를 보내서 뭔가 일을 꾸밀(?) 수 있게 해보고 싶은마음에 시작.. 물론 양쪽 프로그램은 내가 직접 만든다는 가정하에..

  세상에 선구자는 많으니 역시나..자료를 찾기 시작.. 이전에 간단하나마 만든 것도 있고..

  말재주는 없으니 본론으로 들어가서 그냥 소스 정리..


[사용된 WinAPI 함수 및 중요 키워드]

FindWindow, SendMessage, WM_COPYDATA


[Send : C#]



[Source]

    public class MessageHelper
    {
        [DllImport("User32.dll")]
        private static extern int RegisterWindowMessage(string lpString);

        [DllImport("User32.dll", EntryPoint = "FindWindow")]
        public static extern Int32 FindWindow(String lpClassName, String lpWindowName);

        //For use with WM_COPYDATA and COPYDATASTRUCT
        [DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = false, EntryPoint = "SendMessage")]
        public static extern int SendMessage(int hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);

        //For use with WM_COPYDATA and COPYDATASTRUCT
        [DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = false, EntryPoint = "PostMessage")]
        public static extern int PostMessage(int hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);

        //For use with WM_COPYDATA and COPYDATASTRUCT*
        [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "SendMessage")]
        private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        [DllImport("User32.dll", CharSet = CharSet.Auto, EntryPoint = "SendMessage")]
        public static extern int SendMessage(int hWnd, int Msg, int wParam, int lParam);

        [DllImport("User32.dll", CharSet = CharSet.Auto, EntryPoint = "PostMessage")]
        public static extern int PostMessage(int hWnd, int Msg, int wParam, int lParam);

        [DllImport("User32.dll", EntryPoint = "SetForegroundWindow")]
        public static extern bool SetForegroundWindow(int hWnd);

        public const int WM_USER = 0x400;
        public const int WM_SENDER = WM_USER + 4444;
        public const int WM_COPYDATA = 0x4A;

        //Used for WM_COPYDATA for string messages
        //[StructLayout(LayoutKind.Sequential)] 
        public struct COPYDATASTRUCT
        {
            public int dwData;
            public int cbData;
            //[MarshalAs(UnmanagedType.LPStr)]
            public IntPtr lpData;
        }

        public bool BringAppToFront(int hWnd)
        {
            return SetForegroundWindow(hWnd);
        }

        public int SendWindowsStringMessage(int hWnd, int wParam, string command)
        {
            int result = 0;

            if (hWnd != 0)
            {
                byte[] sarr = System.Text.Encoding.Default.GetBytes(command);
                int len = sarr.Length;

                COPYDATASTRUCT cds = new COPYDATASTRUCT();
                //cds.dwData = (IntPtr)100;
                cds.dwData = 0;
                cds.cbData = len + 1;
                //cds.cbData = Marshal.SizeOf(cds);
                cds.lpData = Marshal.StringToHGlobalAnsi(command);
                //cds.lpData = Marshal.StringToCoTaskMemAnsi(command);

                result = SendMessage(hWnd, WM_COPYDATA, wParam, ref cds);
            }

            return result;
        }

        public int SendWindowsMessage(int hWnd, int Msg, int wParam, int lParam)
        {
            int result = 0;

            if (hWnd != 0)
            {
                result = SendMessage(hWnd, Msg, wParam, lParam);
            }

            return result;
        }

        public int GetWindowID(string className, string windowName)
        {
            return FindWindow(className, windowName);
        }
    }





[Use]


int hWnd = messageHelper.GetWindowID(null, windowCaption);
messageHelper.SendWindowsStringMessage(hWnd, 0, String);



[Receive : C++]


[Source]


WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{  
    switch ( msg )   
    {  
    case WM_COPYDATA:  
        {  
            //Used for WM_COPYDATA for string messages  
            struct COPYDATASTRUCT  
            {  
                int dwData;  
                int cbData;  
                PVOID lpData;  
            };  
  
            COPYDATASTRUCT* cp = (COPYDATASTRUCT*)lParam;  
  
            if( NULL != cp )  
            {  
                String strCommand = "";  
                char szCommand[256] = {0,};  
                  
                memcpy( szCommand, cp->lpData, cp->cbData );  
                  
                if(NULL != szCommand)  
                {  
					/// ToDo  
					/// 여기서 받은 문자열로 할 일 하면 됨.  
					/// dwData는 여기선 의미가 없긴한데 enum이나 int 그대로 써서  
					/// switch문 등으로 분기시켜서 여러가지 다양한 처리를 하려고
					/// 처음 소스 짠사람이 만든 것 같다.  
					/// 다른 일도 분류해서 처리하려면 사용하자.  
                }  
            }  
        }  
        break;  
    }  
}  




[주의]

WM_COPYDATA 는 PostMessage로 날릴 수 없다고 한다. SendMessage를 사용하자.

(상대쪽에서 받기 전에 이쪽에서 메모리 해제 되있으면 AV뜨기때문에..)

참고 링크 : http://lunapiece.net/?mid=Tips&listStyle=webzine&document_srl=3780&sort_index=readed_count&order_type=desc


P.s. 마음대로 되지 않고 삽질도 많이해서 여기저기 쓰이지 않는 주석이 남아있긴 하지만.. 삽질기념(?) 그냥 냅두기..

       하도 검색하고 다녀서 참조한 곳을 다 찾기엔 좀 걸리거나 빼먹을 수 도 있을 것 같다. 출처를 찾으러 가야지..



[참조]

http://boycook.wordpress.com/2008/07/29/c-win32-messaging-with-sendmessage-and-wm_copydata/

http://kofmania.tistory.com/45

http://xarfox.tistory.com/45

http://jacking.tistory.com/134

http://www.hoons.kr/board.aspx?Name=qacshap&Mode=2&BoardIdx=10465&Key=&Value=

http://lunapiece.net/?mid=Tips&listStyle=webzine&document_srl=3780&sort_index=readed_count&order_type=desc

- 그 외 못 적은 곳은.. 죄송합니다..;;



반응형
Posted by blueasa
, |