星期三, 7月 05, 2006

More about Interop in Managed , Unmanaged C++

上一篇不能動,應該說是沒效,系統不會shutdown。
所以從基本開始。

原來這種呼叫以前SDK 的DLL的動作叫 Interop.
MSDN 這一篇有範例跟說明 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcwlkSysimportAttributeTutorial.asp

第一段: 從Managed Application 呼叫 Unmanaged Code.

範例是呼叫 User32.dll的 MessageBox
#using <mscorlib.dll>
using namespace System::Runtime::InteropServices;
// for DllImportAttribute

namespace SysWin32
{
[DllImport("user32.dll", EntryPoint = "MessageBox", CharSet = CharSet::Unicode)]
int MessageBox(void* hWnd, wchar_t* lpText, wchar_t* lpCaption,
unsigned int uType);
}

int main( )
{
SysWin32::MessageBox( 0, L"Hello world!", L"Greetings", 0 );
}
DllImport用來告訴compiler有個function在User32.dll中。
EntryPoint說名function的進入點,如果沒寫,default就是與function同名。
CharSet 會讓呼叫時依據執行平台的內容 呼叫MessageBox或是MessageBoxW。
之後就是copy MessageBox的 declaration..並且加上 extern "C"

但是我用VC++ Express + Platform SDK 2003 Server build上面的example,會出現Unicode沒定義的錯誤。
把 CharSet = Unicode改為 CharSet=CharSet::Unicode後就OK了。
follow 這一篇
Specify a Character Set,用CharSet.Unicode,結果出現 mscorlib.dll::interopService::CharSet 沒有 . 動作,所以改為CharSet::之後就自動出現幾個Charset property 可以選了 :)


這一篇有個更簡單的..
呼叫User32.dll的 GetSystemMetrics
// compile with: /clr
using namespace System;
using namespace System::Runtime::InteropServices;

value class Win32 {
public:
[DllImport("User32.dll")]
static int GetSystemMetrics(int);

enum class SystemMetricIndex {
// Same values as those defined in winuser.h.
SM_CXSCREEN = 0,
SM_CYSCREEN = 1
};
};

int main() {
int hRes = Win32::GetSystemMetrics( safe_cast<int>(Win32::SystemMetricIndex::SM_CXSCREEN) );
int vRes = Win32::GetSystemMetrics( safe_cast<int>(Win32::SystemMetricIndex::SM_CYSCREEN) );
Console::WriteLine("screen resolution: {0},{1}", hRes, vRes);
}
.這一篇是structure argument的例子 kernel32.dll的 GetSystemTime.
一樣,先宣告GetSystemTime argument的structure。
但是原WORD keyword已經不支援,所以要改成short。

#include "stdafx.h"

using namespace System;
using namespace System::Runtime::InteropServices;

typedef struct _SYSTEMTIME {
short wYear;
short wMonth;
short wDayOfYear;
short wDay;
short wHour;
short wMinute;
short wSecode;
short wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME;


[DllImport ("kernel32.dll")]
extern "C" void GetSystemTime(SYSTEMTIME* pSystemTime);


int main(array<System::String ^> ^args)
{
SYSTEMTIME *pSystemTime = new SYSTEMTIME();
GetSystemTime(pSystemTime);
Console::WriteLine("Current Month is {0}", pSystemTime->wMonth);
return 0;
}
和原來文章的code不一樣的的方式,WriteLine的argument有用__box prefix,compile時出現 error : __box需要 /clr : oldstyle,所以我就把他拿掉了。

同樣一篇,接著是"Dealing with String,似乎可以解決uncode的問題..(因為他直接使用MessageBoxW):
#include "stdafx.h"

using namespace System;
using namespace System::Runtime::InteropServices;

[DllImport("user32.dll")]
extern "C" void MessageBox(int hWnd, char* lpText, char* lpCaption, unsigned int uType);

int main(array<System::String ^> ^args)
{
MessageBox(0,"Hi There!","888",0);
Console::WriteLine(L"Hello World");
return 0;
}
和原Example不一樣得的方式 MessageBox argument char* 在example是String *,但是compile出現System::String cast問題,參考前一個例子,用wchar_t代,結果出現 char[10]不能轉換成 wchar,才改用char *。

執行結果,即使使用中文String也ok,所以大概是可以吧。


所以使用Win32API的方式大概是..先找到API所在的DLL,再找到API的prototype。
將原Win32 SDK的argument type name改為Managed C++ typename (where is the conversion table ?)。
就可以直接使用了。

沒有留言:

張貼留言