|
윈도우 앱스토어에 올려진 Note Memo에 대한 개발 사이트
Note Memo
개발 정보를 기록해두기 위한 사아트이다
현재 Note Memo는 UWP를 이용해서 개발을 했다
이를 WinUI3 (c++) 로 변경을 하고 있고 아래에는 이 개발을 위한 자료가 충분치 않아서
개발을 위해 분석한 자료들을 올리고 있다
Note Memo를 개발하는 데 사용된 Neget 패키지
1) Microsoft.Graphics.Win2D
WinUI3 (c++)
WinUI 3은 Windows 앱 SDK(Windows SDK에서 완전히 분리됨)와 함께 제공되는 기본 UI 플랫폼 구성 요소
기존의 Windows 개발과 uwp를 섞은 것이라고 한다
uwp보다는 IDL 파일을 많이 사용하고 있다
xml과 c++의 인터페이스로 IDL을 사용하고 있다
인터페이스 정의 언어 (IDL)
소프트웨어 컴포넌트의 인터페이스를 묘사하기 위한 명세 언어
IDL은 다른 두 개의 시스템을 연결하는 다리 역할을 한다
처음에는 임시로 기록이 필요한 모든 사항을 적어놓았다가
나중에 개발이 어느정도 되면 정리를 할 생각이다
Microsoft 인터페이스 정의 언어 3.0 참조 - Windows UWP applications | Microsoft Learn
컨트롤을 만들고 IDL에 인터페이스 함수를 추가해야
함수를 부를 수 있다
[default_interface]
runtimeclass DocumentControl : Microsoft.UI.Xaml.Controls.UserControl
{
DocumentControl();
Int32 MyProperty;
void Invalidate();
}
DocumentControl().Invalidate();
와 같이 사용된다
co_await 호출을 하려면
IAsyncAction를 리턴하는 함수 내에서 사용이 가능하다
IAsyncAction EW_InsertTableAsync(IWorkcontroller* doc, Args& args)
{
EyeWORD::InsertDialog dialog;
auto content = MainWindow::m_mainWindow->Content();
dialog.XamlRoot(content.XamlRoot());
dialog.Title(winrt::box_value(L"Save ?"));
dialog.PrimaryButtonText(L"Yes");
dialog.SecondaryButtonText(L"No");
dialog.CloseButtonText(L"Cancel");
dialog.DefaultButton(winrt::Microsoft::UI::Xaml::Controls::ContentDialogButton::Primary);
ContentDialogResult result = co_await dialog.ShowAsync();
}
1) 윈도우에 의한 Event 처리
.h
void CoreWindow_Activated(IInspectable sender, ::winrt::Microsoft::UI::Xaml::WindowActivatedEventArgs args);
void CoreWindow_VisibilityChanged(IInspectable sender, ::winrt::Microsoft::UI::Xaml::WindowVisibilityChangedEventArgs args);
void CoreWindow_Closed(IInspectable sender, ::winrt::Microsoft::UI::Xaml::WindowEventArgs args);
.cpp
VisibilityChanged(TypedEventHandler<IInspectable, winrt::Microsoft::UI::Xaml::WindowVisibilityChangedEventArgs>
(this, &MainWindow::CoreWindow_VisibilityChanged));
Activated(TypedEventHandler<IInspectable, winrt::Microsoft::UI::Xaml::WindowActivatedEventArgs>
(this, &MainWindow::CoreWindow_Activated));
Closed(TypedEventHandler<IInspectable, winrt::Microsoft::UI::Xaml::WindowEventArgs>
(this, &MainWindow::CoreWindow_Closed));
2) 창에 의한 Event 처리
.h
void CoreWindow_KeyDown(IInspectable const& sender, ::winrt::Microsoft::UI::Xaml::Input::KeyRoutedEventArgs args);
void CoreWindow_KeyUp(IInspectable const& sender, ::winrt::Microsoft::UI::Xaml::Input::KeyRoutedEventArgs args);
void CoreWindow_PointerPressed(IInspectable const& sender, PointerRoutedEventArgs args);
void CoreWindow_PointerCaptureLost(IInspectable const& sender, PointerRoutedEventArgs args);
void CoreWindow_PointerEntered(IInspectable const& sender, PointerRoutedEventArgs args);
void CoreWindow_PointerExited(IInspectable const& sender, PointerRoutedEventArgs args);
void CoreWindow_PointerMoved(IInspectable const& sender, PointerRoutedEventArgs args);
void CoreWindow_PointerReleased(IInspectable const& sender, PointerRoutedEventArgs args);
void CoreWindow_PointerWheelChanged(IInspectable const& sender, PointerRoutedEventArgs args);
void CoreWindow_SizeChanged(IInspectable const& sender, SizeChangedEventArgs args);
void CoreWindow_GotFocus(IInspectable const& sender, RoutedEventArgs args);
void CoreWindow_LostFocus(IInspectable const& sender, RoutedEventArgs args);
void CoreWindow_DoubleTapped(IInspectable const& sender, DoubleTappedRoutedEventArgs args);
.cpp
Content().KeyDown(KeyEventHandler(this, &DocumentControl::CoreWindow_KeyDown));
Content().KeyUp(KeyEventHandler(this, &DocumentControl::CoreWindow_KeyUp));
Content().PointerPressed(PointerEventHandler(this, &DocumentControl::CoreWindow_PointerPressed));
Content().PointerCaptureLost(PointerEventHandler(this, &DocumentControl::CoreWindow_PointerCaptureLost));
Content().PointerEntered(PointerEventHandler(this, &DocumentControl::CoreWindow_PointerEntered));
Content().PointerExited(PointerEventHandler(this, &DocumentControl::CoreWindow_PointerExited));
Content().PointerMoved(PointerEventHandler(this, &DocumentControl::CoreWindow_PointerMoved));
Content().PointerReleased(PointerEventHandler(this, &DocumentControl::CoreWindow_PointerReleased));
Content().PointerWheelChanged(PointerEventHandler(this, &DocumentControl::CoreWindow_PointerWheelChanged));
Content().DoubleTapped(DoubleTappedEventHandler(this, &DocumentControl::CoreWindow_DoubleTapped));
Content().GotFocus(RoutedEventHandler(this, &DocumentControl::CoreWindow_GotFocus));
Content().LostFocus(RoutedEventHandler(this, &DocumentControl::CoreWindow_LostFocus));
SizeChanged(SizeChangedEventHandler(this, &DocumentControl::CoreWindow_SizeChanged));
CoreWindow_PointerPressed를 처리하기 위해서는 위의 2개를 include해야 한다
TypeName 구조체 (winrt::xaml_typename)
구조체 이름을 리턴한다
RegisterForWindow()
Content().KeyDown(winrt::Microsoft::UI::Xaml::Input::KeyEventHandler(this, &DocumentControl::CoreWindow_KeyDown));
uwp에서는 Active Windows를 가지고 KeyDown 처리를 추가했는데
WinUI3에서는 Content() 를 가지고 처리를 한다
의존성 등록
DependencyProperty::Register
PropertyName, 속성의 타입, 부모의 타입, 속성 메타데이터 지정
winrt::Microsoft::UI::Xaml::DependencyProperty
예제1)
Microsoft::UI::Xaml::DependencyProperty::Register(
L"AnotherBrush",
winrt::xaml_typename<winrt::Microsoft::UI::Xaml::Media::Brush>(),
winrt::xaml_typename<winrt::UnpackagedDesktopApp::MyUserControl>(),
Microsoft::UI::Xaml::PropertyMetadata(nullptr)
);
예제2)
public static readonly DependencyProperty LabelProperty = DependencyProperty.Register(
nameof(Label),
typeof(String),
typeof(ImageWithLabelControl),
new PropertyMetadata(null)
);
Timer를 만드는 코드
void MainWindow::CreateForTimer()
{
std::chrono::milliseconds timespan(5);
TimeSpan ts(timespan);
m_isTimerEnabled = false;
m_dispatcherTimer = DispatcherTimer();
m_dispatcherTimer.Interval(ts);
m_tickToken = m_dispatcherTimer.Tick({ this, &MainWindow::OnTick });
m_dispatcherTimer.Start();
}
Frame 호출
rootFrame.Navigate(xaml_typename(), box_value(e.Arguments()));
HWND 처리
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(m_window);
UINT GetDpiForWindow( [in] HWND hwnd );
DPI_AWARENESS_UNAWARE DPI의 기본 값은 96('USER_DEFAULT_SCREEN_DPI'으로 정의됨)으로 설정됩니다.
DPI_AWARENESS_SYSTEM_AWARE 시스템 DPI입니다.
DPI_AWARENESS_PER_MONITOR_AWARE 창이 있는 모니터의 DPI입니다.
std::function
C++11 부터 추가된 기능으로, C의 함수 포인터를 대체한다.
std::function<void()> f1 = std::bind(&RulerControl::Test, this);
f1();
A test;
// 매개변수로 객체를 전달해야한다
std::function<void(A&, int, int)> func3 = &A::addAndPrint;
func3(test, 10, 20);
Callable
struct S {
void operator()(int a, int b) { std::cout << "a + b = " << a + b << std::endl; }
};
auto f = [](int a, int b) { std::cout << "a + b = " << a + b << std::endl; };
int some_func1(const std::string& a) {
std::cout << "Func1 호출! " << a << std::endl;
return 0;
}
struct S {
void operator()(char c) { std::cout << "Func2 호출! " << c << std::endl; }
};
int main() {
std::function<int(const std::string&)> f1 = some_func1;
std::function<void(char)> f2 = S();
std::function<void()> f3 = []() { std::cout << "Func3 호출! " << std::endl; };
class A {
int c;
public:
A(int c) : c(c) {}
int some_func() {
std::cout << "비상수 함수: " << ++c << std::endl;
return c;
}
int some_const_function() const {
std::cout << "상수 함수: " << c << std::endl;
return c;
}
static void st() {}
};
A a(5);
std::function<int(A&)> f1 = &A::some_func;
std::function<int(const A&)> f2 = &A::some_const_function;
vector<int> a(1);
vector<int> b(2);
vector<int> c(3);
vector<int> d(4);
vector<vector<int>> container;
container.push_back(b);
container.push_back(d);
container.push_back(a);
container.push_back(c);
vector<int> size_vec(4);
std::transform(container.begin(), container.end(), size_vec.begin(),
&vector<int>::size);
PropertyChanged 예제
event PropertyChangedEventHandler PropertyChanged;
if (this->DispatcherQueue().HasThreadAccess())
else
DispatcherQueue().TryEnqueue([strongThis = get_strong(), this, strMessage, severity]
{ UpdateStatus(strMessage, severity); });
milisecond 로 TimeSpan 초기화 하기
std::chrono::milliseconds timespan(500);
TimeSpan timeout(timespan);
리소스 처리
class DeviceManager
{
private:
IDWriteFactory2* m_dwriteFactory = nullptr;
IDWriteTextFormat* m_textFormat = nullptr;
IDWriteTextLayout* m_textLayout = nullptr;
public:
IDWriteFactory2* GetWriteFactory()
{
if (m_dwriteFactory == nullptr) {
DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory2),
reinterpret_cast<::IUnknown**>(&m_dwriteFactory)
);
}
return m_dwriteFactory;
}
bool CreateTextFormat(wchar_t const* fontFamilyName, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, FLOAT fontSize)
{
const wchar_t* lang = Windows::Globalization::ApplicationLanguages::Languages().GetAt(0).c_str();
HRESULT hr = m_dwriteFactory->CreateTextFormat(
fontFamilyName,
nullptr,
weight,
style,
DWRITE_FONT_STRETCH_NORMAL,
fontSize,
lang,
&m_textFormat);
return SUCCEEDED(hr);
}
bool CreateTextLayout(wchar_t const* string, int length)
{
const float MAX_TEXT_LAYOUT_SIZE = 500;
HRESULT hr = m_dwriteFactory->CreateTextLayout(
string,
static_cast<UINT32>(length),
m_textFormat,
MAX_TEXT_LAYOUT_SIZE,
MAX_TEXT_LAYOUT_SIZE,
&m_textLayout);
return SUCCEEDED(hr);
}
int GetHeight()
{
DWRITE_TEXT_METRICS textMetrics;
m_textLayout->GetMetrics(&textMetrics);
return (int)std::round(textMetrics.height);
}
int GetWidth()
{
DWRITE_TEXT_METRICS textMetrics;
m_textLayout->GetMetrics(&textMetrics);
return (int)std::round(textMetrics.widthIncludingTrailingWhitespace);
}
} g_DeviceManager;
HFONT SystemCreateFont(int cHeight, int /*cWidth*/, int cWeight, DWORD bItalic, DWORD /*bUnderline*/, DWORD /*bStrikeOut*/, DWORD /*iCharSet*/, LPCWSTR pszFaceName, UINT code)
{
vector<stringCW> strings;
SystemClass::GetAlternativeFont(strings, pszFaceName, code, false);
DWRITE_FONT_WEIGHT weight = DWRITE_FONT_WEIGHT_NORMAL;
DWRITE_FONT_STYLE style = DWRITE_FONT_STYLE_NORMAL;
if (cWeight == FW_BOLD)
weight = DWRITE_FONT_WEIGHT_BOLD;
if (bItalic)
style = DWRITE_FONT_STYLE_ITALIC;
for (auto fontName : strings) {
if (g_DeviceManager.CreateTextFormat(fontName.c_str(), weight, style, (float)cHeight))
return (HFONT)100;
}
return nullptr;
}
int SystemGetFontHeight(IFontStyle* pFontStyle, bool bBold, bool bItalic, bool bUnderline, BYTE charSet, const wchar_t* facename)
{
wchar_t string[2] = { ' ', '\0', };
if (SystemClass::CreateFont(BASE_FONT_SIZE, 0, bBold ? FW_BOLD : FW_NORMAL, bItalic,
bUnderline, 0, charSet, facename, false) == nullptr)
return BASE_FONT_SIZE;
if (!g_DeviceManager.CreateTextLayout(string, 1))
return BASE_FONT_SIZE;
return g_DeviceManager.GetHeight();
}
int SystemGetSurrogateCharWidth(HCHAR* ch, bool bBold, bool bItalic, bool bUnderline, BYTE charSet, const wchar_t* facename)
{
unsigned int value = (unsigned int)CUTF16toUTF32(ch[0], ch[1]);
if (SystemCreateFont(BASE_FONT_SIZE, 0, bBold ? FW_BOLD : FW_NORMAL, bItalic,
bUnderline, 0, charSet, facename, value) == nullptr)
return BASE_FONT_SIZE;
if (!g_DeviceManager.CreateTextLayout(ch, 2))
return BASE_FONT_SIZE;
return g_DeviceManager.GetWidth();
}
int SystemGetZeroWidthJoinerWidth(HCHAR* ch, bool bBold, bool bItalic, bool bUnderline, BYTE charSet, const wchar_t* facename)
{
if (SystemCreateFont(BASE_FONT_SIZE, 0, bBold ? FW_BOLD : FW_NORMAL, bItalic,
bUnderline, 0, charSet, facename, 0) == nullptr)
return BASE_FONT_SIZE;
if (!g_DeviceManager.CreateTextLayout(ch, 5))
return BASE_FONT_SIZE;
return g_DeviceManager.GetWidth();
}
bool SystemGetCharWidth(UINT iFirstChar, UINT iLastChar, LPINT lpBuffer, bool bBold, bool bItalic, bool bUnderline, BYTE charSet, const wchar_t* facename)
{
if (IsSpecialCode(iFirstChar)) {
vector<stringCW> alternativeList;
SystemClass::GetAlternativeFont(alternativeList, facename, iFirstChar, false);
if (SystemClass::CreateFont(BASE_FONT_SIZE, 0, bBold ? FW_BOLD : FW_NORMAL, bItalic,
bUnderline, 0, charSet, alternativeList.at(0).c_str(), false) == nullptr)
return false;
} else {
if (SystemClass::CreateFont(BASE_FONT_SIZE, 0, bBold ? FW_BOLD : FW_NORMAL, bItalic,
bUnderline, 0, charSet, facename, false) == nullptr)
return false;
}
wchar_t ch = static_cast<wchar_t>(iFirstChar);
for (UINT index = iFirstChar; index <= iLastChar; index++, ch++) {
wchar_t string[2] = { ch, '\0', };
lpBuffer[ch - iFirstChar] = BASE_FONT_SIZE;
if (!g_DeviceManager.CreateTextLayout(string, 1))
continue;
lpBuffer[ch - iFirstChar] = g_DeviceManager.GetWidth();
}
return true;
}
winrt::hstring LString(winrt::hstring str)
{
return Resources::ResourceLoader().GetString(str);;
}