2012-10-05 23 views
8

के साथ WM_COPYDATA पासिंग स्ट्रक्चर के साथ सी #+ प्रक्रिया में सी # प्रोग्राम से मैं एक विरासत सी ++/क्ली एमएफसी एप्लिकेशन के साथ संवाद करने के लिए SendMessage के साथ WM_COPYDATA का उपयोग करना चाहता हूं।सी # से सी ++ प्रक्रिया स्ट्रिंग

मैं स्ट्रिंग ऑब्जेक्ट्स वाली एक प्रबंधित संरचना को पास करना चाहता हूं।

मैं SendMessage जुर्माना के उपयोग के लिए C++ एप्लिकेशन को हैंडल पा सकता हूं।

थोड़ा सा मुझे नहीं पता कि संरचना और उसके तारों को कैसे घुमाया जा सकता है और दूसरी तरफ पढ़ा जा सकता है। विशेष रूप से इसमें गैर-ब्लिटेबल्स होते हैं।

क्या लोग सोचते हैं कि यह संभव है? मैं इस पर काम करना जारी रखूंगा, लेकिन किसी ऐसे व्यक्ति को पकड़ लेगा जिसने इस तरह की चीज की है जो मुझे बता रही है कि यह काम नहीं करेगा।

यहां कुछ डेमो कोड है यदि यह एक सी ++/क्ली प्रोग्राम था और इसे काम करना मुश्किल नहीं है। हालांकि, मैं इसे नेट क्लास लाइब्रेरी में रखना चाहता हूं ताकि इसे आसानी से फिर से उपयोग किया जा सके।

//Quick demonstation code only, not correctly styled 
int WINAPI WinMain(HINSTANCE hInstance, 
       HINSTANCE hPrevInstance, 
       LPSTR lpCmdLine, 
       int nCmdShow) 
{    
    struct MessageInfo 
    { 
     int  nVersion; 
     char szTest[ 10 ];   
    }; 

    MessageInfo sMessageInfo; 

    sMessageInfo.nVersion = 100; 
    strcpy(sMessageInfo.szTest, "TEST"); 

    COPYDATASTRUCT CDS; 

    CDS.dwData = 1; //just for test 
    CDS.cbData = sizeof(sMessageInfo); 
    CDS.lpData = &sMessageInfo; 

    //find running processes and send them a message 
    //can't just search for "MYAPP.exe" as will be called "MYAPP.exe *32" on a 64bit machine 
    array<System::Diagnostics::Process^>^allProcesses = System::Diagnostics::Process::GetProcesses(); 

    for each (System::Diagnostics::Process^ targetProcess in allProcesses) 
    {   
     if (targetProcess->ProcessName->StartsWith("MYAPP", System::StringComparison::OrdinalIgnoreCase)) 
     { 
      HWND handle = static_cast<HWND>(targetProcess->MainWindowHandle.ToPointer()); 

      BOOL bReturnValue = SendMessage(handle, WM_COPYDATA, (WPARAM)0, (LPARAM)&CDS) == TRUE; 
     } 
    } 

    return 0; 
} 

उत्तर

9

मेरे पास यह काम कर रहा है।

एक सरल तरीका स्ट्रिंग को एक स्ट्रिंग में क्रमबद्ध करना और स्ट्रिंग को स्थानांतरित करना है। swhistlesoft ब्लॉग सहायक था http://www.swhistlesoft.com/blog/2011/11/19/1636-wm_copydata-with-net-and-c

यह सरल संदेश प्रदान करने के लिए पर्याप्त हो सकता है। यदि आवश्यक हो तो संरचना को दूसरे छोर पर फिर से बनाया जा सकता है।

यदि किसी भी स्ट्रिंग के साथ एक स्ट्रक्चर को मार्शल किया जाना है तो यह एक निश्चित आकार होना चाहिए, यह मुख्य बात है जो मुझे नहीं मिल रही थी।

MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 9) 

मूल रूप से आकार सेट C++ आकार जो हमारे मामले में एक TCHAR szTest है मैच के लिए [9];

स्थानांतरित करने के लिए।मैं के रूप में करना था ग # ग ++ (/ CLI) से WM_COPYDATA के माध्यम से नेट struct इस प्रकार है:

COPYDATASTRUCT cd = new COPYDATASTRUCT(); 
    cd.dwData = 2; 

    cd.cbData = parameters.Length + 1; 
    cd.lpData = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(parameters); 

    IntPtr cdBuffer = IntPtrAlloc(cd); 

    messageReceived = ((int)SendMessage(targetProcess.MainWindowHandle, WM_COPYDATA, IntPtr.Zero, cdBuffer)) != 0; 

सी में स्ट्रिंग प्राप्त करने के लिए ++:

else if(pCDS->dwData == 2) 
    { 
     //copydata message 
     CString csMessage = (LPCTSTR)pCDS->lpData; 
     OutputDebugString("Copydata message received: " + csMessage); 
    } 

[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] 
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam); 

    [System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] 
    static extern bool SetForegroundWindow(IntPtr hWnd); 

public static uint WM_COPYDATA = 74; 

//from swhistlesoft 
public static IntPtr IntPtrAlloc<T>(T param) 
    { 
     IntPtr retval = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(param)); 
     System.Runtime.InteropServices.Marshal.StructureToPtr(param, retval, false); 
     return (retval); 
    } 

//from swhistlesoft 
    public static void IntPtrFree(IntPtr preAllocated) 
    { 
     if (IntPtr.Zero == preAllocated) throw (new Exception("Go Home")); 
     System.Runtime.InteropServices.Marshal.FreeHGlobal(preAllocated); 
     preAllocated = IntPtr.Zero; 
    } 

    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)] 
    struct COPYDATASTRUCT 
    { 
     public uint dwData; 
     public int cbData; 
     public IntPtr lpData; 
    } 

    /// <summary> 
    /// Dot net version of AppInfo structure. Any changes to the structure needs reflecting here. 
    /// struct must be a fixed size for marshalling to work, hence the SizeConst entries 
    /// </summary> 
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)] 
    struct AppInfoDotNet 
    { 
     public int nVersion;    

     [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 9)] 
     public string test; 
    }; 

एक स्ट्रिंग भेजने के लिए

संरचना भेजने के लिए:

  AppInfoDotNet appInfo = new AppInfoDotNet(); 
      appInfo.test = "a test"; 

      COPYDATASTRUCT cds3; 
      cds3.dwData = 1; 
      cds3.cbData = System.Runtime.InteropServices.Marshal.SizeOf(appInfo); 

      IntPtr structPtr = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(System.Runtime.InteropServices.Marshal.SizeOf(appInfo)); 
      System.Runtime.InteropServices.Marshal.StructureToPtr(appInfo, structPtr, false); 

      cds3.lpData = structPtr; 

      IntPtr iPtr = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(System.Runtime.InteropServices.Marshal.SizeOf(cds3)); 
      System.Runtime.InteropServices.Marshal.StructureToPtr(cds3, iPtr, false); 

      messageReceived = ((int)SendMessage(targetProcess.MainWindowHandle, WM_COPYDATA, IntPtr.Zero, iPtr)) != 0; 

      System.Runtime.InteropServices.Marshal.FreeCoTaskMem(iPtr); 
      System.Runtime.InteropServices.Marshal.FreeCoTaskMem(structPtr); 

फिर से C++ ceive struct:

LRESULT CMainFrame::OnCopyData(WPARAM wParam, LPARAM lParam) 
{ 
    LRESULT lResult = FALSE; 

    COPYDATASTRUCT *pCDS = (COPYDATASTRUCT*)lParam; 

    //Matching message type for struct 
    if(pCDS->dwData == 1) 
    { 
     AppInfo *pAppInfo = (AppInfo*)pCDS->lpData 
     lResult = true; 
    } 

कृपया ध्यान दें इस डेमो कोड है और जरूरतों स्टाइल के मामले में काम करते हैं, अपवाद हैंडलिंग आदि, आदि ...

+0

धन्यवाद। WM_COPYDATA में कस्टम स्ट्रक्चर के लिए, आपका उदाहरण केवल इस साइट पर पाया गया एकमात्र काम था। –

1

प्रलेखन से:

डेटा पारित किया जा रहा वस्तुओं डेटा प्राप्त आवेदन के लिए सुलभ नहीं करने के लिए संकेत या अन्य संदर्भ नहीं होनी चाहिए।

तो आपको अपनी स्ट्रिंग को COPYDATASTRUCT.lpData में पैक करने की आवश्यकता है। आप प्रत्येक स्ट्रिंग के लिए एक अधिकतम लंबाई है तो आप एक निश्चित लंबाई संरचना में यह एम्बेड कर सकते हैं

typedef struct tagMYDATA 
{ 
    char s1[80]; 
    char s2[120]; 
} MYDATA; 

आप अंत में स्ट्रिंग डाल दिया और एक हैडर स्ट्रिंग डेटा के बाद का उपयोग कर सकते आप केवल एक चर लंबाई स्ट्रिंग है, तो

typedef struct tagMYDATA 
{ 
    int value1; 
    float value2; 
    int stringLen; 
} MYDATAHEADER; 

MyCDS.cbData = sizeof(MYDATAHEADER)+(int)stringData.size(); 
MyCDS.lpData = new BYTE[MyCDS.cbData]; 
memcpy(MyCDS.lpData,&dataHeader,sizeof*(MYDATAHEADER); 
StringCbCopyA (
    ((BYTE*)MyCDS.lpData)+sizeof*(MYDATAHEADER) 
    ,stringData.size() 
    ,stringData.c_str()); 

आप एक से अधिक चर लंबाई तार आप अभी भी एक शीर्ष लेख का उपयोग और हर तार के साथ साथ एक डबल अशक्त टर्मिनेटर के लिए अधिक स्थान का आवंटन, या एक एक्सएमएल स्ट्रिंग में सब कुछ को क्रमानुसार कर सकते हैं।