PDA

View Full Version : SendMessage و COPYDATASTRUCT



menevlster
چهارشنبه 12 آبان 1389, 15:52 عصر
سلام
لطفا درمورد SendMessage توضیح دهید که چه توع پارامترهایی را می توان با COPYDATASTRUCT ارسال کرد و آیا با COPYDATASTRUCT می توان یک COM interfaces را ارسال کرد یا نه(یعنی کار IDispatch را انجام دهد).

menevlster
چهارشنبه 12 آبان 1389, 21:43 عصر
سلام
مدیران محترم که به سئوال بنده جواب ندادند خواهشا به جوابی که من از msdn forums گرفتم توجه کنند و به زبان فارسی توضیح دهند

1.1 It is not possible to pass COM interfaces pointers from one application to another using the WM_COPYDATA message.
1.2 Even within one application, it may not be legitimate to simply copy COM interface pointers. One has to be aware of COM apartments.

2. Between 2 applications, it will be necessary to make some kind of arrangement to transfer COM interface pointers via marshaling.

توضیح برای بند 2

1.1 One way is to design a COM interface (IInterfaceTransfer, say) the purpose of which is to specifically transfer an IUnknown* pointer across 2 clients.

1.2 For example it could have 2 methods : 1.2.1 set_IUnknown([in] IUnknown* pIUnknown);
1.2.2 get_IUnknown([out] IUnknown** ppIUnknownReceiver);
2. Then implement such an IInterfaceTransfer interface in a SINGLETON COM class housed in a COM EXE Server. 2.1 If you do this via ATL, you can use the DECLARE_CLASSFACTORY_SINGLETON() macro.
2.2 As a singleton COM class housed in a COM EXE server, all clients effectively use the exact same instance.
2.3 Transfer any required COM interface pointers via the set_IUnknown() and get_IUnknown() methods.
2.4 When one client app calls set_IUnknown(), the input interface pointer is marshaled from this client (client 1, say) to the IInterfaceTransfer object.
2.5 Next, somehow inform the other client application (client 2, say) that client 1 has just transferred an interface pointer. You can use PostMessage() or SendMessage() using a private windows message.
2.6 After client 2 has been informed of this, it calls get_IUnknown(). The interface pointer from client 1 is then marshaled from the IInterfaceTransfer object to client 2.


ممنون.

r00tkit
چهارشنبه 12 آبان 1389, 21:52 عصر
من از COM چیزی نمی دونم ولی می خوای برات ترجمه کنم ؟ تا وقتی که استاد موسوی هستش غم چی رو می خورید یه پیام خصوصی بده و حالشو ببر

menevlster
چهارشنبه 12 آبان 1389, 23:17 عصر
سلام
ممنون از توجهتون به سئوال بنده ولی من در ترجمه مشکلی ندارم خواهشا از دوستانی که در مورد Com اطلاعاتی دارند کمک کنند.

sh4mid
پنج شنبه 13 آبان 1389, 00:29 صبح
سلام
ببین این به دردت می خوره
http://msdn.microsoft.com/en-us/magazine/cc301563.aspx

mehdi.mousavi
پنج شنبه 13 آبان 1389, 18:14 عصر
سلام.
برای استفاده از WM_COPYDATA شما می تونید داده مورد نظرتون رو از Heap (یا حتی Stack) بگیرید، سپس آدرس به حافظه گرفته شده رو در lpData Member از COPYDATASTRUCT قرار بدید و اونو به سمت Application مقصد ارسال کنید. حالا دیگه این داده شما هر Structure پیچیده ای میتونه باشه و اهمیتی نداره. اما اینجا چند نکته وجود داره که باید بهش دقت کرد.

ابتدا اینکه هنگام ارسال پیام، باید دقت کنید که از SendMessage استفاده می کنید، یا از PostMessage. طبیعتا اگر از SendMessage استفاده کنید، تا وقتی WM_COPYDATA سمت App دریافت کننده پردازش نشده باشه، Thread ارسال کنندهT، فعالیتش متوقف میشه. نکته بعدی اینکه باید دقت کنید هنگام دریافت این پیام، App مقصد هرگز نباید سعی کنه حافظه اشاره شده توسط lParam رو آزاد کنه. اگر کاری که می خواهید انجام بدید زمان بر هستش، باید یه نسخه Local در App ی مقصد (از اون داده دریافت شده) نگهدارید و بلافاصله اجازه بدید فعالیت Thread ادامه پیدا کنه. همچنین دقت کنید که lParam فقط هنگام پردازش پیام معتبر هستش (با فرض اینکه از SendMessage استفاده کرده باشید) زیرا بدین ترتیب App ی مبدا تضمین میکنه که حافظه اشاره شده در آدرسی که lParam بهتون نشون میده، Valid هستش.

اما در مورد COM داستان بگونه دیگه ای هستش. همونطوریکه اطلاع دارید، در COM باید تعیین کنیم که Component ما در چه آپارتمانی قرار می گیره، Single-Threaded Apartment، Multi-Thread Apartment یا Free-Threaded Apartment. ضمن اینکه Thread ای که قراره Component ما رو Host کنه، توسط CoCreateInstance قبلش Initialize میشه. همه اینها به این معنی هستش که Pointer به COM Interface مورد نظر شما در Client Application، باید برای استفاده در Receiving App (منظورم App ای هستش که قراره از رسیدن WM_COPYDATA مطلع بشه) مارشال بشه و بدون شک WM_COPYDATA جایگاهی نیست که این اتفاق بخواد در اون رخ بده.

اگر اشتباه نکنم، شما COM Component ای رو در App مبدا خودتون ایجاد کرده اید و حالا مایلید تا Interface گرفته شده از اون Component رو به App ی دیگه ای ارسال کنید. سوالی که اینجا پیش میاد اینه که چرا اجازه نمیدید تا همون Receiving App، خودش، COM Component مورد نظر رو ایجاد کنه؟ در واقع چرا فقط با یک پیام ساده Receiving App رو مطلع نمی کنید تا خودش اقدام به CI کردن اون Component کنه؟ چون اینطور که از سوال شما بر میاد، کل این روند در یک Machine Boundary داره انجام میشه، پس Receiving App شما نیز به COM Server هدف دسترسی داره.

من از روشی که در MSDN Group ها بهتون پیشنهاد شده چندان خوشم نیومد. بهتون گفتن که یه COM Server ایجاد کنید که وظیفه انتقال اون Interface (و بالطبع Marshaling اونو) بعهده بگیره. پیشنهاد دادن که کلاس مربوطه در COM Server رو Singleton بگیرید و روی Interface ای که در اون پیاده سازی کرده اید (تحت عنوان IInterfaceTransfer) دو متود Set و Get قرار بدید. بدین ترتیب، در App ارسال کننده می تونید COM Server رو ایجاد کنید، IUnknown مورد نظر رو (با استفاده از متود Set) در اون قرار بدید و با ارسال پیامی به Receiving App، اونو از رسیدن این Interface مطلع کنید. در Receiving App با استفاده از متود Get اون IUnknown رو بگیرید (که دیگه Marshal شده) و مابقی کار رو پیش ببرید.

اما من میپرسم چه دلیلی داره که شما اینکارو کنید؟ چرا COM Server مورد نظر رو همون سمت Receiving App خودتون Init نمی کنید؟ گذشته از اینها، ممکنه مشکلتون با یک Connection Point حل بشه، اگر قرار هستش فقط Notification هایی به اونیکی App ارسال کنید.

متاسفانه نیازتون رو دقیق مطرح نکردید تا بتونم دقیقتر پاسخ بدم.

موفق باشید.

menevlster
پنج شنبه 13 آبان 1389, 23:07 عصر
سلام مهدی جان واقعا گل کاشتید
در پروژه من Receiving App همان ffmpeg (http://ffmpeg.arrozcru.org/wiki/index.php?title=MSVC) نقش media convertor دارد که به زبان C و با mingw کمپایل شده (غیر قابل کمپایل با MSVC) و در Client Application پروژه اصلی به زبان C++‎‎‎‎, C#‎‎‎ نوشته شده حال اگر DirectShow (http://msdn.microsoft.com/en-us/library/dd375454%28VS.85%29.aspx) درClient Application ایجاد شود(چه با زبان C#‎‎ یا C++‎‎‎)به راحتی انجام پذیر است ولی ایجاد DirectShow و کنترل آن در زبان C با توجه به منابع محدود بسیار مشکل است.
به این دلیل با ایجاد COM objects نظیر IBaseFilter در Client Application وارسال آن به ffmpeg این مشکل حل می شود