Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++] [WinApi] Problem z dodaniem Drag&drop

Ostatnio zmodyfikowano 2021-03-19 19:32
Autor Wiadomość
idepozapalki
Temat założony przez niniejszego użytkownika
[C++] [WinApi] Problem z dodaniem Drag&drop
» 2021-03-18 12:48:01
W zamierzeniu aplikacja ma pobierać linki z rzuconych w nią plików.
Chciałbym żeby oprogramowane były 3 scenariusze.
1 - aplikacja nie uruchomiona, pliki rzucane są na exe'ka
To już oprogramowałem. Użyłem funkcji

CommandLineToArgvW(GetCommandLine(), &argCount);

2 - aplikacja uruchomiona, pliki rzucane są na otwarte okno
To też już działa z użyciem zdarzenia
case WM_DROPFILES:

3 - aplikacja uruchomiona, pliki są rzucane w exe'ka
Tutaj mam problem, rzucanie nie działa.
Po rzuceniu pliku słyszę jedynie dzwięk okienka informacyjnego, ale nic poza tym.
Kilka razy widziałem "mrugnięcie" okienka, ale nie wiem jak to sprawdzić.
Nie wiem też jak użyć debugera w VisualStudio wg 3 scenariusza.

Co już zrobiłem:
Sprawdziłem forum, ale tu nie znalazłem rozwiązania.

Przejrzałem stackoverflow, tam nie zauważyłem rozwiązania 3 scenariusza.
Tam znalazłem inspiracje do pierwszego scenariusza.

Odwiedziłem tą stronę:
https://bugrazoid.ru/doku.php?id=develop:winapi:draganddrop
Przetestowałem wszystkie aplikacje, ale żadna nie działa wg 3 scenariusza.

Zacząłem czytać te informacje, ale nie wiem czy tam jest rozwiązanie dla mnie. To jest w trakcie
https://devblogs.microsoft.com/oldnewthing/20100503-00/?p=14183

Znalazłem kilka rozwiązań ale z użyciem MFC

A tu to co sam poskładałem:
C/C++
//-----------------------------------------------
//
// Program napisany w Microsoft Visual C++ 2019
// Aplikacja napisana w C++ z uzyciem WinApi
//
//-----------------------------------------------

#include <windows.h>
#include <tchar.h>
#include <commctrl.h>
#include <vector>
#include <string>

#pragma comment(lib,"comctl32.lib")

// deklaracje globalnych uchwytow i zmiennych
MSG msg;
HWND hWnd;
HINSTANCE hInst;

const TCHAR * ApplicationTitle = _T( "Aplikacja" );

//---------------------------------------------------------
//
// Wyciaga rozszerzenie ze sciezki
//
//---------------------------------------------------------
std::wstring GetExtension( const std::wstring & fileName ) {
   
auto pos = fileName.rfind( L"." );
   
if( pos == std::wstring::npos )
       
 pos = - 1;
   
   
return std::wstring( fileName.begin() + pos + 1, fileName.end() );
}

//---------------------------------------------------------
//
// Obsluga rzuconych plikow
//
//---------------------------------------------------------
void DropFile( WPARAM wParam ) {
   
TCHAR lpszFile[ MAX_PATH ] = { 0 };
   
UINT uFile = 0;
   
HDROP hDrop =( HDROP ) wParam;
   
int index, count, length;
   
count = DragQueryFile( hDrop, 0xFFFFFFFF, NULL, 0 ); // ilosc rzuconych plikow
    // petla bedzie czytac rzucone pliki
   
for( index = 0; index < count; ++index ) {
       
length = DragQueryFile( hDrop, index, NULL, 0 );
       
if( length > 0 ) {
           
TCHAR * fname = new TCHAR[ static_cast < size_t >( length ) + 1 ]; // rzutuje
           
DragQueryFile( hDrop, index, fname, length + 1 );
           
// konwertuje tchar do wstringa
           
std::wstring sciezka( & fname[ 0 ] );
           
std::wstring rozszerzenie;
           
rozszerzenie = GetExtension( sciezka );
           
// filtruje pliki i do przetwarzania puszczam tylko aptsource
           
if( rozszerzenie == L"txt" ) {
               
MessageBox( NULL, fname, L"Rzucone pliki", MB_OK );
           
}
           
delete[ ] fname;
       
}
    }
   
DragFinish( hDrop );
}

//---------------------------------------------------------
//
// Procedura obsługująca wiadomości dla okna, wywoływana przez
// MS-Windows przy okazji różnych zdarzeń, które należy obsłużyć
//
//--------------------------------------------------------------
static LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
   
switch( msg )
   
{
       
       
// Obsluga drag & drop
   
case WM_DROPFILES: {
           
DropFile( wParam );
           
break;
       
}
       
       
// reakcja na zamkniecie okienka
   
case WM_CLOSE:
       
PostQuitMessage( 0 );
       
return 0;
       
       
// komunikat od systemu wyslany po zamknieciu okienka
   
case WM_DESTROY:
       
PostQuitMessage( 0 );
       
return 0;
       
       
default:
       
return DefWindowProc( hWnd, msg, wParam, lParam );
       
break;
   
}
   
return DefWindowProc( hWnd, msg, wParam, lParam );
}

void InitMainWnd() {
   
HINSTANCE hInstance = GetModuleHandle( 0 );
   
WNDCLASSEX wClass = { 0 };
   
ZeroMemory( & wClass, sizeof( WNDCLASSEX ) );
   
wClass.style = CS_HREDRAW | CS_VREDRAW;
   
wClass.cbClsExtra = 0;
   
wClass.cbWndExtra = 0;
   
wClass.cbSize = sizeof( WNDCLASSEX );
   
wClass.hbrBackground =( HBRUSH )( COLOR_BTNFACE + 1 );
   
wClass.hInstance = hInstance;
   
wClass.lpfnWndProc =( WNDPROC ) WndProc;
   
wClass.lpszClassName = _T( "My Window Class" );
   
wClass.hCursor = LoadCursor( 0, IDC_ARROW );
   
wClass.hIcon = LoadIcon( NULL, IDI_APPLICATION );
   
wClass.hIconSm = LoadCursor( NULL, IDC_ARROW );
   
wClass.lpszMenuName = 0;
   
// Rejestrujemy klasę okna w Windows.
   
if( !RegisterClassEx( & wClass ) ) {
       
int nResult = GetLastError();
       
MessageBox( NULL, _T( "Nie utworzono żadnej klasy!" ), _T( "Błąd" ), MB_ICONERROR );
   
}
   
// zabezpieczenie przed uruchomieniem kolejnej instancji w przypadku startu z linii polecen
   
HWND hOther = FindWindow( wClass.lpszClassName, NULL );
   
if( hOther )
   
{
       
PostQuitMessage( 0 );
   
}
}

//---------------------------------------------------------
//
// Funkcja dodajca linki rzucone w aplikacje
//
//---------------------------------------------------------
void LaunchCommandLineElements() {
   
LPWSTR * szArgList;
   
int argCount; // liczba argumentów
   
szArgList = CommandLineToArgvW( GetCommandLine(), & argCount ); //pobiera linię poleceń
    // zaczynam od drugiego elementu z linii polcen
   
for( int i = 1; i < argCount; i++ ) {
       
TCHAR * plik = szArgList[ i ];
       
std::wstring wplik( plik );
       
std::wstring rozszerzenie;
       
rozszerzenie = GetExtension( wplik );
       
// filtruje pliki i do przetwarzania, puszczam tylko aptsource
       
if( rozszerzenie == L"txt" ) {
           
MessageBox( NULL, szArgList[ i ], L"Zawartość listy argumentów", MB_OK );
       
}
    }
   
LocalFree( szArgList );
}

//---------------------------------------------------------
//
// Funkcja tworząca główne okno
//
//---------------------------------------------------------
HWND CreateMainWnd() {
   
return
   
CreateWindowEx(
   
WS_EX_CLIENTEDGE,
   
_T( "My Window Class" ),
   
ApplicationTitle,
   
WS_OVERLAPPED | WS_CAPTION | WS_BORDER | WS_MINIMIZEBOX | WS_SYSMENU,
   
0,
   
0,
   
400,
   
400,
   
NULL,
   
NULL,
   
hInst,
   
NULL );
}

//---------------------------------------------------------
//
// Główna funkcja w Windows , od której uruchamiany jest program
//
//---------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int showCmd )
{
   
OleInitialize( NULL ); // uruchamiam obsługę dragdrop
   
InitMainWnd(); // startuje głowne okno
   
hWnd = CreateMainWnd(); // create the main window!
   
if( !hWnd ) {
       
int nResult = GetLastError();
       
MessageBox( NULL, _T( "Nie utworzono żadnego okna!" ), _T( "Błąd" ), MB_ICONERROR );
   
}
   
DragAcceptFiles( hWnd, true ); // Drag & Drop w starym stylu
   
LaunchCommandLineElements(); // obsługa linków rzuconych w aplikację
   
ShowWindow( hWnd, showCmd ); // Utworzone okno wyświetlamy na ekranie  
   
UpdateWindow( hWnd ); // Uaktualniamy treść okna
   
ZeroMemory( & msg, sizeof( MSG ) );
   
while( msg.message != WM_QUIT ) { // Rozpoczynamy pętlę obsługi wiadomości napływających do naszego okna.
       
if( PeekMessage( & msg, 0, 0, 0, PM_REMOVE ) ) {
           
TranslateMessage( & msg ); // Przekształcamy wiadomość
           
DispatchMessage( & msg ); // Wysyłamy ją do procedury okna
       
}
       
else {
           
        }
    }
   
OleUninitialize();
   
return 0;
}
P-178307
pekfos
» 2021-03-18 17:08:45
Mignięcie aplikacji w scenariuszu 3 wynika zapewne z tego:
C/C++
// zabezpieczenie przed uruchomieniem kolejnej instancji w przypadku startu z linii polecen
HWND hOther = FindWindow( wClass.lpszClassName, NULL );
if( hOther )
{
   
PostQuitMessage( 0 );
}
To sugeruje że chcesz by w scenariuszu nr 3 plik rzucony na exe był obsłużony przez wcześniej działającą instancję. W tym celu musisz użyć jakiegoś mechanizmu komunikacji między procesami i przesłać odpowiednią informację do pierwszego procesu.
https://docs.microsoft.com/en-us/windows/win32/ipc/interprocess-communications
Możesz użyć na przykład named pipe w trybie message (PIPE_TYPE_MESSAGE). Pierwsza instancja by tworzyła pipe i nasłuchiwała przychodzących wiadomości w osobnym wątku.
https://docs.microsoft.com/en-us/windows/win32/ipc/named-pipes

Nie wiem też jak użyć debugera w VisualStudio wg 3 scenariusza.
Uruchom program w tle, potem drugą instancję pod debuggerem z podaniem ścieżki do pliku w opcjach uruchomieniowych.
P-178308
idepozapalki
Temat założony przez niniejszego użytkownika
» 2021-03-18 23:24:45
Masz rację, to miganie wynika właśnie z tego fragmentu kodu. Przy rzucie linka tworzona była kolejna instancja której okno przykrywało okno tej pierwszej, a ten fragment go wygaszał.
Planowałem, żeby w aplikacji była jedna instancja. Przy częstym używaniu programu każde uruchomienie, byłoby kolejnym okienkiem i kolejnym elemencikiem na pasku. Poza tym gdy jest jedna instancja to w łatwy sposób można w jakimś ListView zgromadzić wyniki pracy programu, a tak trzeba przeglądać te pojedyncze instancje.

Dlatego użyłem kawałka kodu z odcinka kursu pt "Jedna instancja", ale okazało się, że ma on też minusy w połączeniu z uruchamianiem przez rzut. Sprawdziłem też mutex'a, ale oczywiście efekt ten sam.

Możliwa jest też opcja, że aplikacja będzie tray'u koło zegarka, ale nie wiem jak w tym przypadku wyglądałaby historia z kolejnymi instancjami.

Starałem się w prosty sposób jakoś rozwiązać mój kłopot.
Pierwsze podejście jest takie:

Na początku dodaje zmienną globalną:
bool jednainstancja = TRUE ;

i zmieniam kod głównej części:
C/C++
//---------------------------------------------------------
//
// Główna funkcja w Windows , od której uruchamiany jest program
// kodowanie zależne od ustawień projektu
//
//---------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int showCmd )
{
   
OleInitialize( NULL ); // uruchamiam obsługę dragdrop
   
LaunchCommandLineElements();
   
InitMainWnd(); // startuje głowne okno
   
if( jednainstancja ) {
       
hWnd = CreateMainWnd(); // create the main window!
       
if( !hWnd ) {
           
int nResult = GetLastError();
           
MessageBox( NULL, _T( "Nie utworzono żadnego okna!" ), _T( "Błąd" ), MB_ICONERROR );
       
}
       
DragAcceptFiles( hWnd, true ); // Drag & Drop w starym stylu
       
ShowWindow( hWnd, showCmd ); // Utworzone okno wyświetlamy na ekranie  
       
UpdateWindow( hWnd ); // Uaktualniamy treść okna
   
}
   
ZeroMemory( & msg, sizeof( MSG ) );
   
while( msg.message != WM_QUIT ) { // Rozpoczynamy pętlę obsługi wiadomości napływających do naszego okna.
       
if( PeekMessage( & msg, 0, 0, 0, PM_REMOVE ) ) {
           
TranslateMessage( & msg ); // Przekształcamy wiadomość
           
DispatchMessage( & msg ); // Wysyłamy ją do procedury okna
       
}
       
else {
           
        }
    }
   
OleUninitialize();
   
return 0;
}

Na pierwszy rzut oka spełnia to swoje zadanie, ale to tylko pierwsze wrażenie. Uruchomienie na początku LaunchCommandLineElements() spowoduje że w każdym przypadku dostanę linki, ALE linki te będę miał dużo wcześniej zanim pojawi się okno gdzie mogę pokazać na bieżąco efekty pracy programu. Trochę bez sensu będzie obróbka pliku zanim jeszcze pojawi się okno programu. Przy dużych plikach takie zachowanie programu byłby frustrujący, bo rzucasz link do dużej porcji tekstu a tu nic się nie dzieje.
Ten kod wyżej nie rozwiązał też problemu z miganiem aplikacją. Sprawdzałem i niby nie powinna się pojawiać, bo dołożony warunek omija kawałek wyświetlający i uaktualniający okno ale mimo to coś tam migało.
Chciałbym uniknąć takiego "druciarstwa".

Po cichu miałem nadzieję że drag&drop ma gdzieś metodę/funkcję która przy uruchomionej aplikacji mogłaby pobrać linka rzuconego w exe'ka - ale do tej pory się nie doszukałem.

Na ten moment nie mam praktyki z named pipe, ale postaram się odrobić tą lekcję.
P-178309
pekfos
» 2021-03-19 00:06:59
Mignięcie bierze się z tego, że PostQuitMessage() nie zamyka programu, a tylko zleca jego zamknięcie. Zdążysz w tym czasie utworzyć okno. W tej sytuacji powinieneś raczej wyjść z WinMain(), albo użyć czegoś w stylu exit().

Możliwa jest też opcja, że aplikacja będzie tray'u koło zegarka, ale nie wiem jak w tym przypadku wyglądałaby historia z kolejnymi instancjami.
Każda instancja by generowała osobną ikonę w tray'u, co raczej odpada.
P-178310
idepozapalki
Temat założony przez niniejszego użytkownika
» 2021-03-19 00:49:08
Poprawiłem to do takiej postaci.

C/C++
//---------------------------------------------------------
//
// Główna funkcja w Windows , od której uruchamiany jest program
// kodowanie zależne od ustawień projektu
//
//---------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int showCmd )
{
   
LaunchCommandLineElements();
   
if( jednainstancja ) {
       
InitMainWnd(); // startuje głowne okno
       
hWnd = CreateMainWnd(); // create the main window!
       
if( !hWnd ) {
           
int nResult = GetLastError();
           
MessageBox( NULL, _T( "Nie utworzono żadnego okna!" ), _T( "Błąd" ), MB_ICONERROR );
       
}
       
DragAcceptFiles( hWnd, true ); // Drag & Drop w starym stylu
       
ShowWindow( hWnd, showCmd ); // Utworzone okno wyświetlamy na ekranie  
       
UpdateWindow( hWnd ); // Uaktualniamy treść okna
       
ZeroMemory( & msg, sizeof( MSG ) );
       
while( msg.message != WM_QUIT ) { // Rozpoczynamy pętlę obsługi wiadomości napływających do naszego okna.
           
if( PeekMessage( & msg, 0, 0, 0, PM_REMOVE ) ) {
               
TranslateMessage( & msg ); // Przekształcamy wiadomość
               
DispatchMessage( & msg ); // Wysyłamy ją do procedury okna
           
}
           
else {
            }
        }
    }
   
return 0;
}

Teoretycznie przy uruchomionej aplikacji po rzucie linków powinna uruchomić się tylko funkcja LaunchCommandLineElements(), a później program powinien skoczyć do return 0 i omijam całość okienkową.
Testy pokazują jednak coś innego. Szczególnie to widać gdy przesunie się okno z "z pozycji startowej" w lewym górnym rogu ekranu gdzieś z bok. Po kliknięciu w okienko komunikatu z linkiem w "pozycji startowej" pojawia się "duch" okna.
Nie rozumiem tej sytuacji, bo właściwie to omijam wszystko "okienkowe" i tam nic nie powinno się pojawiać.

Rzeczywiście więcej ikonek w tray'u to tylko przeniesienie tam problemu.

----------------------------------------------------------------------------

Jednak popełniłem błąd. Funkcja InitMainWnd() MUSI być przed warunkiem sprawdzającym instancję.
Teraz zaczęło wszystko działać poprawnie.
Potestuję jednak całość trochę dla pewności.
P-178311
pekfos
» 2021-03-19 15:40:34
Czemu dokładnie służy zmienna jednainstancja? Jak dotąd nie widać w kodzie by robiła cokolwiek.
P-178314
DejaVu
» 2021-03-19 16:53:24
Ode mnie mały hint (nie związany z Twoim problemem):
C/C++
const TCHAR * ApplicationTitle = _T( "Aplikacja" );

Na Twoim miejscu olałbym całkowicie TCHAR/char i implementował wszystko już na wide stringach tj.
C/C++
const wchar_t * ApplicationTitle = L"Aplikacja";

Powody:
  • wsparcie 'Multibyte wide string' jest oznaczone w Visual Studio już jako deprecated (will be removed in future);
  • używając wide stringów zawsze będziesz wspierał poprawnie kodowanie wielu języków;
  • tam gdzie będzie konieczna konwersja danych na widestring (np. wyświetlanie zawartości plików) od razu rzuci Ci się w oczy, bo będziesz miał błąd kompilacji i tym samym kompilator zmusi Ciebie do zrobienia względnie poprawnej konwersji danych.

P-178317
idepozapalki
Temat założony przez niniejszego użytkownika
» 2021-03-19 19:32:57
@pekfos
Zmienna jednainstancja służy do wykrywania pojawiania się kolejnych instancji i tak jak sugerowałeś do wyjścia z WinMain().
Za pierwszym razem aplikacja startuje normalnie. Po rzuceniu linkami w uruchomionego exe'ka w funkcji InitMainWnd() wykrywam próbę uruchomienia kolejnej instancji i przy jej wykryciu ustawiam:
jednainstancja = FALSE ;
teraz pętla w części głównej omija całą "windosową" część i kończy WinMain na return 0;
Dzięki temu unikam wszelkiego migania. Testowałem i jest ok.

Teraz muszę przemyśleć jak przekazywać linki z pierwszego uruchomienia i z rzuconych linków do części okienkowej.

Załączam całość kodu na dole.


@DejaVu
W moim przypadku najlepiej sprawdzają się TCHAR w takiej postaci.
Ten kod to uproszczona część większej całości i wrzuciłem tutaj działające minimum, żeby pokazać z czym mam problem i nie zaciemniać perspektywy windosową częścią i innymi zbędnymi dodatkami.
W pierwszej fazie miałem to wszystko mieszane, trochę TCHAR trochę wchar_t. Przy "sprzątaniu" kodu konwersja do wchar_t okazała się bardziej upierdliwa (kompilator bulwersował się o różne rzutowania) i okazało się że makro _T( ) zadziało wszędzie, dlatego jest jak jest.
Przy okazji poznałem różne mikrosoftowe wynalazki typu:
LPSTR, LPCSTR LPWSTR, LPCWSTR, LPTSTR, LPCTSTR
używane to tu to tam.

C/C++
//-----------------------------------------------
//
// Program napisany w Microsoft Visual C++ 2019
// Aplikacja napisana w C++ z uzyciem WinApi
//
//-----------------------------------------------

#include <windows.h>
#include <tchar.h>
#include <commctrl.h>
#include <string>

#pragma comment(lib,"comctl32.lib")

// deklaracje globalnych uchwytow i zmiennych
MSG msg;
HWND hWnd;
HINSTANCE hInst;

bool jednainstancja = TRUE;

const TCHAR * ApplicationTitle = _T( "Aplikacja" );

//---------------------------------------------------------
//
// Wyciaga rozszerzenie ze sciezki
//
//---------------------------------------------------------
std::wstring GetExtension( const std::wstring & fileName ) {
   
auto pos = fileName.rfind( L"." );
   
if( pos == std::wstring::npos )
       
 pos = - 1;
   
   
return std::wstring( fileName.begin() + pos + 1, fileName.end() );
}

//---------------------------------------------------------
//
// Obsluga rzuconych plikow
//
//---------------------------------------------------------
void DropFile( WPARAM wParam ) {
   
TCHAR lpszFile[ MAX_PATH ] = { 0 };
   
UINT uFile = 0;
   
HDROP hDrop =( HDROP ) wParam;
   
int index, count, length;
   
count = DragQueryFile( hDrop, 0xFFFFFFFF, NULL, 0 ); // ilosc rzuconych plikow
    // petla bedzie czytac rzucone pliki
   
for( index = 0; index < count; ++index ) {
       
length = DragQueryFile( hDrop, index, NULL, 0 );
       
if( length > 0 ) {
           
TCHAR * fname = new TCHAR[ static_cast < size_t >( length ) + 1 ]; // rzutuje
           
DragQueryFile( hDrop, index, fname, length + 1 );
           
// konwertuje tchar do wstringa
           
std::wstring sciezka( & fname[ 0 ] );
           
std::wstring rozszerzenie;
           
rozszerzenie = GetExtension( sciezka );
           
// filtruje pliki i do przetwarzania puszczam tylko aptsource
           
if( rozszerzenie == L"txt" ) {
               
MessageBox( NULL, fname, L"Rzucone pliki", MB_OK );
           
}
           
delete[ ] fname;
       
}
    }
   
DragFinish( hDrop );
}

//---------------------------------------------------------
//
// Funkcja dodajca linki rzucone w aplikacje
//
//---------------------------------------------------------
void LaunchCommandLineElements() {
   
LPWSTR * szArgList;
   
int argCount; // liczba argumentów
   
szArgList = CommandLineToArgvW( GetCommandLine(), & argCount ); //pobiera linię poleceń
    // zaczynam od drugiego elementu z linii polcen
   
for( int i = 1; i < argCount; i++ ) {
       
TCHAR * plik = szArgList[ i ];
       
std::wstring wplik( plik );
       
std::wstring rozszerzenie;
       
rozszerzenie = GetExtension( wplik );
       
// filtruje pliki i do przetwarzania, puszczam tylko aptsource
       
if( rozszerzenie == L"txt" ) {
           
MessageBox( NULL, szArgList[ i ], L"Zawartość listy argumentów", MB_OK );
       
}
    }
   
LocalFree( szArgList );
}

//---------------------------------------------------------
//
// Procedura obsługująca wiadomości dla okna, wywoływana przez
// MS-Windows przy okazji różnych zdarzeń, które należy obsłużyć
//
//--------------------------------------------------------------
static LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
   
switch( msg )
   
{
       
       
// Obsluga drag & drop
   
case WM_DROPFILES: {
           
DropFile( wParam );
           
           
break;
       
}
       
       
// reakcja na zamkniecie okienka
   
case WM_CLOSE:
       
PostQuitMessage( 0 );
       
return 0;
       
       
// komunikat od systemu wyslany po zamknieciu okienka
   
case WM_DESTROY:
       
PostQuitMessage( 0 );
       
return 0;
       
       
default:
       
return DefWindowProc( hWnd, msg, wParam, lParam );
       
break;
   
}
   
return DefWindowProc( hWnd, msg, wParam, lParam );
}

void InitMainWnd() {
   
HINSTANCE hInstance = GetModuleHandle( 0 );
   
WNDCLASSEX wClass = { 0 };
   
ZeroMemory( & wClass, sizeof( WNDCLASSEX ) );
   
wClass.style = CS_HREDRAW | CS_VREDRAW;
   
wClass.cbClsExtra = 0;
   
wClass.cbWndExtra = 0;
   
wClass.cbSize = sizeof( WNDCLASSEX );
   
wClass.hbrBackground =( HBRUSH )( COLOR_BTNFACE + 1 );
   
wClass.hInstance = hInstance;
   
wClass.lpfnWndProc =( WNDPROC ) WndProc;
   
wClass.lpszClassName = _T( "My Window Class" );
   
wClass.hCursor = LoadCursor( 0, IDC_ARROW );
   
wClass.hIcon = LoadIcon( NULL, IDI_APPLICATION );
   
wClass.hIconSm = LoadCursor( NULL, IDC_ARROW );
   
wClass.lpszMenuName = 0;
   
// Rejestrujemy klasę okna w Windows.
   
if( !RegisterClassEx( & wClass ) ) {
       
int nResult = GetLastError();
       
MessageBox( NULL, _T( "Nie utworzono żadnej klasy!" ), _T( "Błąd" ), MB_ICONERROR );
   
}
   
/*
 HANDLE hMutex = CreateMutex(NULL, FALSE, _T("MyMutex") );
 if (hMutex && GetLastError() != 0) {
  jednainstancja = FALSE ;
//  MessageBox(NULL, _T("Ta aplikacja jest już uruchomiona."), _T("WindowsTest"), MB_ICONEXCLAMATION);
  PostQuitMessage(0);
 }
*/
   
    // zabezpieczenie przed uruchomieniem kolejnej instancji w przypadku startu z linii polecen
   
HWND hOther = FindWindow( wClass.lpszClassName, NULL );
   
if( hOther )
   
{
       
jednainstancja = FALSE;
       
PostQuitMessage( 0 );
   
}
   
}

//---------------------------------------------------------
//
// Funkcja tworząca główne okno
//
//---------------------------------------------------------
HWND CreateMainWnd() {
   
return
   
CreateWindowEx(
   
WS_EX_CLIENTEDGE,
   
_T( "My Window Class" ),
   
ApplicationTitle,
   
WS_OVERLAPPED | WS_CAPTION | WS_BORDER | WS_MINIMIZEBOX | WS_SYSMENU,
   
0,
   
0,
   
400,
   
400,
   
NULL,
   
NULL,
   
hInst,
   
NULL );
}

//---------------------------------------------------------
//
// Główna funkcja w Windows , od której uruchamiany jest program
// kodowanie zależne od ustawień projektu
//
//---------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int showCmd )
{
   
LaunchCommandLineElements();
   
InitMainWnd(); // startuje głowne okno
   
if( jednainstancja ) {
       
hWnd = CreateMainWnd(); // create the main window!
       
if( !hWnd ) {
           
int nResult = GetLastError();
           
MessageBox( NULL, _T( "Nie utworzono żadnego okna!" ), _T( "Błąd" ), MB_ICONERROR );
       
}
       
DragAcceptFiles( hWnd, true ); // Drag & Drop w starym stylu
       
ShowWindow( hWnd, showCmd ); // Utworzone okno wyświetlamy na ekranie  
       
UpdateWindow( hWnd ); // Uaktualniamy treść okna
       
ZeroMemory( & msg, sizeof( MSG ) );
       
while( msg.message != WM_QUIT ) { // Rozpoczynamy pętlę obsługi wiadomości napływających do naszego okna.
           
if( PeekMessage( & msg, 0, 0, 0, PM_REMOVE ) ) {
               
TranslateMessage( & msg ); // Przekształcamy wiadomość
               
DispatchMessage( & msg ); // Wysyłamy ją do procedury okna
           
}
           
else {
            }
        }
    }
   
return 0;
}
P-178318
« 1 »
  Strona 1 z 1